Merge "Broadcast lifecycle events for instant apps"
diff --git a/Android.bp b/Android.bp
index 2ea4894..82589c1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12,6 +12,642 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// Build the master framework library.
+
+// READ ME: ########################################################
+//
+// When updating this list of aidl files, consider if that aidl is
+// part of the SDK API. If it is, also add it to the list in Android.mk
+// that is preprocessed and distributed with the SDK. This list should
+// not contain any aidl files for parcelables, but the one below should
+// if you intend for 3rd parties to be able to send those objects
+// across process boundaries.
+//
+// READ ME: ########################################################
+
+java_library {
+ name: "framework",
+
+ 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/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/IInputForwarder.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/ISearchManager.aidl",
+ "core/java/android/app/ISearchManagerCallback.aidl",
+ "core/java/android/app/IServiceConnection.aidl",
+ "core/java/android/app/IStopUserCallback.aidl",
+ "core/java/android/app/job/IJobCallback.aidl",
+ "core/java/android/app/job/IJobScheduler.aidl",
+ "core/java/android/app/job/IJobService.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/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/trust/IStrongAuthTracker.aidl",
+ "core/java/android/app/trust/ITrustManager.aidl",
+ "core/java/android/app/trust/ITrustListener.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/slice/ISliceManager.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/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/crossprofile/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/IOnPermissionsChangeListener.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/database/IContentObserver.aidl",
+ ":libcamera_client_aidl",
+ ":libcamera_client_framework_aidl",
+ "core/java/android/hardware/IConsumerIrService.aidl",
+ "core/java/android/hardware/ISerialManager.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/IFingerprintService.aidl",
+ "core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl",
+ "core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.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/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/IFusedLocationHardware.aidl",
+ "core/java/android/hardware/location/IFusedLocationHardwareSink.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/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/net/ICaptivePortal.aidl",
+ "core/java/android/net/IConnectivityManager.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/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/os/IBatteryPropertiesListener.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",
+ "core/java/android/os/IIncidentManager.aidl",
+ "core/java/android/os/IIncidentReportCompletedListener.aidl",
+ "core/java/android/os/IIncidentReportStatusListener.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",
+ "core/java/android/os/IStatsCompanionService.aidl",
+ "core/java/android/os/IStatsManager.aidl",
+ "core/java/android/os/IThermalEventListener.aidl",
+ "core/java/android/os/IThermalService.aidl",
+ "core/java/android/os/IUpdateLock.aidl",
+ "core/java/android/os/IUserManager.aidl",
+ "core/java/android/os/IVibratorService.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/security/IKeystoreService.aidl",
+ "core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl",
+ "core/java/android/service/autofill/IAutoFillService.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/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/IRetainSubscriptionsForFactoryResetCallback.aidl",
+ "core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl",
+ "core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl",
+ "core/java/android/service/gatekeeper/IGateKeeperService.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/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/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/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/IAutofillWindowPresenter.aidl",
+ "core/java/android/view/IApplicationToken.aidl",
+ "core/java/android/view/IAppTransitionAnimationSpecsFuture.aidl",
+ "core/java/android/view/IDockedStackListener.aidl",
+ "core/java/android/view/IGraphicsStats.aidl",
+ "core/java/android/view/IGraphicsStatsCallback.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/IRotationWatcher.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/IAppOpsCallback.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/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/car/ICarServiceHelper.aidl",
+ "core/java/com/android/internal/inputmethod/IInputContentUriToken.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/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/IFusedProvider.aidl",
+ "location/java/android/location/IGeocodeProvider.aidl",
+ "location/java/android/location/IGeofenceProvider.aidl",
+ "location/java/android/location/IGnssStatusListener.aidl",
+ "location/java/android/location/IGnssStatusProvider.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",
+ "media/java/android/media/IAudioService.aidl",
+ "media/java/android/media/IAudioFocusDispatcher.aidl",
+ "media/java/android/media/IAudioRoutesObserver.aidl",
+ "media/java/android/media/IMediaHTTPConnection.aidl",
+ "media/java/android/media/IMediaHTTPService.aidl",
+ "media/java/android/media/IMediaResourceMonitor.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/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/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/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/ITelecomService.aidl",
+ "telecomm/java/com/android/internal/telecom/RemoteServiceCallback.aidl",
+ "telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl",
+ "telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl",
+ "telephony/java/android/telephony/mbms/IDownloadStateCallback.aidl",
+ "telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl",
+ "telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl",
+ "telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.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/IImsSmsFeature.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/ISmsListener.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/IMms.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/ISms.aidl",
+ "telephony/java/com/android/internal/telephony/ISub.aidl",
+ "telephony/java/com/android/internal/telephony/ITelephony.aidl",
+ "telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl",
+ "telephony/java/com/android/internal/telephony/IWapPushManager.aidl",
+ "telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl",
+ "wifi/java/android/net/wifi/IWifiManager.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/IWifiScanner.aidl",
+ "wifi/java/android/net/wifi/IRttManager.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",
+ ":netd_aidl",
+ ":vold_aidl",
+ ":installd_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/webkit/EventLogTags.logtags",
+ "core/java/com/android/internal/logging/EventLogTags.logtags",
+
+ ":framework-statslog-gen",
+ ],
+
+ aidl: {
+ local_include_dirs: [
+ // From build/make/core/pathmap.mk FRAMEWORK_BASE_SUBDIRS
+ "core/java",
+ "graphics/java",
+ "location/java",
+ "lowpan/java",
+ "media/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",
+ ],
+
+ include_dirs: [
+ "system/update_engine/binder_bindings",
+ "frameworks/native/aidl/binder",
+ "frameworks/av/camera/aidl",
+ "frameworks/av/media/libaudioclient/aidl",
+ "frameworks/native/aidl/gui",
+ "system/core/storaged/binder",
+ "system/netd/server/binder",
+ "system/vold/binder",
+ "system/bt/binder",
+ ],
+ },
+
+ no_framework_libs: true,
+ libs: [
+ "conscrypt",
+ "okhttp",
+ "bouncycastle",
+ "ext",
+ ],
+
+ static_libs: [
+ "framework-protos",
+ "android.hidl.base-V1.0-java",
+ "android.hardware.cas-V1.0-java",
+ "android.hardware.contexthub-V1.0-java",
+ "android.hardware.health-V1.0-java-constants",
+ "android.hardware.thermal-V1.0-java-constants",
+ "android.hardware.tv.input-V1.0-java-constants",
+ "android.hardware.usb-V1.0-java-constants",
+ "android.hardware.usb-V1.1-java-constants",
+ "android.hardware.vibrator-V1.0-java-constants",
+ "android.hardware.vibrator-V1.1-java-constants",
+ "android.hardware.wifi-V1.0-java-constants",
+ ],
+
+ // Loaded with System.loadLibrary by android.view.textclassifier
+ required: ["libtextclassifier"],
+
+ javac_shard_size: 150,
+
+ dxflags: [
+ "--core-library",
+ "--multi-dex",
+ ],
+}
+
+genrule {
+ name: "framework-statslog-gen",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --java $(out)",
+ out: ["android/util/StatsLog.java"],
+}
+
+gensrcs {
+ name: "framework-javastream-protos",
+ depfile: true,
+
+ tools: [
+ "aprotoc",
+ "protoc-gen-javastream",
+ "soong_zip",
+ ],
+
+ cmd: "mkdir -p $(genDir)/$(in) " +
+ "&& $(location aprotoc) " +
+ " --plugin=$(location protoc-gen-javastream) " +
+ " --dependency_out=$(depfile) " +
+ " --javastream_out=$(genDir)/$(in) " +
+ " -Iexternal/protobuf/src " +
+ " -I . " +
+ " $(in) " +
+ "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
+
+ srcs: ["core/proto/**/*.proto"],
+ output_extension: "srcjar",
+}
+
// Build ext.jar
// ============================================================
java_library {
@@ -65,6 +701,7 @@
"core/proto/android/os/procrank.proto",
"core/proto/android/os/system_properties.proto",
"core/proto/android/service/graphicsstats.proto",
+ "libs/incident/proto/android/privacy.proto",
"tools/streaming_proto/stream.proto",
],
shared: {
diff --git a/Android.mk b/Android.mk
index b1bb1bb..10d11f3 100644
--- a/Android.mk
+++ b/Android.mk
@@ -15,16 +15,8 @@
#
LOCAL_PATH := $(call my-dir)
-# We have a special case here where we build the library's resources
-# independently from its code, so we need to find where the resource
-# class source got placed in the course of building the resources.
-# Thus, the magic here.
-# Also, this module cannot depend directly on the R.java file; if it
-# did, the PRIVATE_* vars for R.java wouldn't be guaranteed to be correct.
-# Instead, it depends on the R.stamp file, which lists the corresponding
-# R.java file as a prerequisite.
-# TODO: find a more appropriate way to do this.
-framework_res_source_path := APPS/framework-res_intermediates/src
+# Load framework-specific path mappings used later in the build.
+include $(LOCAL_PATH)/pathmap.mk
# Build the master framework library.
# The framework contains too many method references (>64K) for poor old DEX.
@@ -35,646 +27,6 @@
# embedded builds use nothing in frameworks/base
ifneq ($(ANDROID_BUILD_EMBEDDED),true)
-include $(CLEAR_VARS)
-
-# Load framework-specific path mappings used later in the build.
-include $(LOCAL_PATH)/pathmap.mk
-
-# FRAMEWORKS_BASE_SUBDIRS comes from build/core/pathmap.mk
-LOCAL_SRC_FILES := \
- $(call find-other-java-files,$(FRAMEWORKS_BASE_SUBDIRS)) \
- $(call all-proto-files-under, core/proto)
-
-# EventLogTags files.
-LOCAL_SRC_FILES += \
- 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/webkit/EventLogTags.logtags \
- core/java/com/android/internal/logging/EventLogTags.logtags \
-
-## READ ME: ########################################################
-##
-## When updating this list of aidl files, consider if that aidl is
-## part of the SDK API. If it is, also add it to the list below that
-## is preprocessed and distributed with the SDK. This list should
-## not contain any aidl files for parcelables, but the one below should
-## if you intend for 3rd parties to be able to send those objects
-## across process boundaries.
-##
-## READ ME: ########################################################
-LOCAL_SRC_FILES += \
- 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/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/IInputForwarder.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/ISearchManager.aidl \
- core/java/android/app/ISearchManagerCallback.aidl \
- core/java/android/app/IServiceConnection.aidl \
- core/java/android/app/IStopUserCallback.aidl \
- core/java/android/app/job/IJobCallback.aidl \
- core/java/android/app/job/IJobScheduler.aidl \
- core/java/android/app/job/IJobService.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/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/trust/IStrongAuthTracker.aidl \
- core/java/android/app/trust/ITrustManager.aidl \
- core/java/android/app/trust/ITrustListener.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/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 \
- ../../system/bt/binder/android/bluetooth/IBluetooth.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothA2dp.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothA2dpSink.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothAvrcpController.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothCallback.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothProfileServiceConnection.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothHeadset.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothHeadsetPhone.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothHealth.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothHealthCallback.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothHidHost.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothPan.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothManager.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothManagerCallback.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothMap.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothMapClient.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothPbap.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothPbapClient.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothSap.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothSocketManager.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothStateChangeCallback.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothHeadsetClient.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothHidDevice.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothHidDeviceCallback.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothGatt.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothGattCallback.aidl \
- ../../system/bt/binder/android/bluetooth/IBluetoothGattServerCallback.aidl \
- ../../system/bt/binder/android/bluetooth/le/IAdvertisingSetCallback.aidl \
- ../../system/bt/binder/android/bluetooth/le/IPeriodicAdvertisingCallback.aidl \
- ../../system/bt/binder/android/bluetooth/le/IScannerCallback.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/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/crossprofile/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/IOnPermissionsChangeListener.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 \
- ../native/libs/binder/aidl/android/content/pm/IPackageManagerNative.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/permission/IRuntimePermissionPresenter.aidl \
- core/java/android/database/IContentObserver.aidl \
- ../av/camera/aidl/android/hardware/ICameraService.aidl \
- ../av/camera/aidl/android/hardware/ICameraServiceListener.aidl \
- ../av/camera/aidl/android/hardware/ICameraServiceProxy.aidl \
- ../av/camera/aidl/android/hardware/ICamera.aidl \
- ../av/camera/aidl/android/hardware/ICameraClient.aidl \
- ../av/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl \
- ../av/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl \
- core/java/android/hardware/IConsumerIrService.aidl \
- core/java/android/hardware/ISerialManager.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/IFingerprintService.aidl \
- core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl \
- core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.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/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/IFusedLocationHardware.aidl \
- core/java/android/hardware/location/IFusedLocationHardwareSink.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/IContextHubService.aidl \
- core/java/android/hardware/location/IContextHubTransactionCallback.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/net/ICaptivePortal.aidl \
- core/java/android/net/IConnectivityManager.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/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/os/IBatteryPropertiesListener.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 \
- core/java/android/os/IIncidentManager.aidl \
- core/java/android/os/IIncidentReportCompletedListener.aidl \
- core/java/android/os/IIncidentReportStatusListener.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 \
- core/java/android/os/IStatsCompanionService.aidl \
- core/java/android/os/IStatsManager.aidl \
- core/java/android/os/IThermalEventListener.aidl \
- core/java/android/os/IThermalService.aidl \
- core/java/android/os/IUpdateLock.aidl \
- core/java/android/os/IUserManager.aidl \
- core/java/android/os/IVibratorService.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/security/IKeystoreService.aidl \
- core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl \
- core/java/android/service/autofill/IAutoFillService.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/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/IRetainSubscriptionsForFactoryResetCallback.aidl \
- core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl \
- core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl \
- core/java/android/service/gatekeeper/IGateKeeperService.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/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/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/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/IAutofillWindowPresenter.aidl \
- core/java/android/view/IApplicationToken.aidl \
- core/java/android/view/IAppTransitionAnimationSpecsFuture.aidl \
- core/java/android/view/IDockedStackListener.aidl \
- core/java/android/view/IGraphicsStats.aidl \
- core/java/android/view/IGraphicsStatsCallback.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/IRotationWatcher.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/IAppOpsCallback.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/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/car/ICarServiceHelper.aidl \
- core/java/com/android/internal/inputmethod/IInputContentUriToken.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/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/IFusedProvider.aidl \
- location/java/android/location/IGeocodeProvider.aidl \
- location/java/android/location/IGeofenceProvider.aidl \
- location/java/android/location/IGnssStatusListener.aidl \
- location/java/android/location/IGnssStatusProvider.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 \
- media/java/android/media/IAudioService.aidl \
- media/java/android/media/IAudioFocusDispatcher.aidl \
- media/java/android/media/IAudioRoutesObserver.aidl \
- media/java/android/media/IMediaHTTPConnection.aidl \
- media/java/android/media/IMediaHTTPService.aidl \
- media/java/android/media/IMediaResourceMonitor.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 \
- ../av/media/libaudioclient/aidl/android/media/IPlayer.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/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/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/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/ITelecomService.aidl \
- telecomm/java/com/android/internal/telecom/RemoteServiceCallback.aidl \
- telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl \
- telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl \
- telephony/java/android/telephony/mbms/IDownloadStateCallback.aidl \
- telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl \
- telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl \
- telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.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/IMms.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/ISms.aidl \
- telephony/java/com/android/internal/telephony/ISub.aidl \
- telephony/java/com/android/internal/telephony/ITelephony.aidl \
- telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
- telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
- telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl \
- wifi/java/android/net/wifi/IWifiManager.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/IWifiScanner.aidl \
- wifi/java/android/net/wifi/IRttManager.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 \
-
-# The following are native binders that need to go with the native component
-# at system/update_engine/binder_bindings/. Use relative path to refer to them.
-LOCAL_SRC_FILES += \
- ../../system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl \
- ../../system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl \
-
-LOCAL_SRC_FILES += \
- ../../system/core/storaged/binder/android/os/IStoraged.aidl \
- ../../system/netd/server/binder/android/net/INetd.aidl \
- ../../system/vold/binder/android/os/IVold.aidl \
- ../../system/vold/binder/android/os/IVoldListener.aidl \
- ../../system/vold/binder/android/os/IVoldTaskListener.aidl \
- ../native/cmds/installd/binder/android/os/IInstalld.aidl \
-
-LOCAL_AIDL_INCLUDES += system/update_engine/binder_bindings
-
-LOCAL_AIDL_INCLUDES += core/java/android/os/StatsLogEventWrapper.aidl
-
-LOCAL_AIDL_INCLUDES += frameworks/base/lowpan/java
-LOCAL_SRC_FILES += \
- 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
-
-# StatsLog generated functions
-statslog_src_dir := $(call intermediates-dir-for,JAVA_LIBRARIES,framework,,COMMON)/statslog
-gen := $(statslog_src_dir)/android/util/StatsLog.java
-$(gen): PRIVATE_PATH := $(LOCAL_PATH)
-$(gen): PRIVATE_CUSTOM_TOOL = $(HOST_OUT_EXECUTABLES)/stats-log-api-gen --java $@
-$(gen): $(HOST_OUT_EXECUTABLES)/stats-log-api-gen
- $(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(gen)
-statslog_src_dir:=
-gen:=
-
-# FRAMEWORKS_BASE_JAVA_SRC_DIRS comes from build/core/pathmap.mk
-LOCAL_AIDL_INCLUDES += \
- $(FRAMEWORKS_BASE_JAVA_SRC_DIRS) \
- frameworks/native/aidl/binder
-
-LOCAL_AIDL_INCLUDES += \
- frameworks/av/camera/aidl \
- frameworks/av/drm/libmediadrm/aidl \
- frameworks/av/media/libaudioclient/aidl \
- frameworks/native/aidl/gui \
- system/core/storaged/binder \
- system/netd/server/binder \
- system/vold/binder \
- system/bt/binder
-
-LOCAL_INTERMEDIATE_SOURCES := \
- $(framework_res_source_path)/android/R.java \
- $(framework_res_source_path)/android/Manifest.java \
- $(framework_res_source_path)/com/android/internal/R.java
-
-# Make sure that R.java and Manifest.java are built before we build
-# the source for this library.
-framework_res_R_stamp := \
- $(call intermediates-dir-for,APPS,framework-res,,COMMON)/src/R.stamp
-LOCAL_ADDITIONAL_DEPENDENCIES := $(framework_res_R_stamp)
-
-LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart conscrypt okhttp bouncycastle ext
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- framework-protos \
- android.hidl.base-V1.0-java \
- android.hardware.cas-V1.0-java \
- android.hardware.contexthub-V1.0-java \
- android.hardware.health-V1.0-java-constants \
- android.hardware.thermal-V1.0-java-constants \
- android.hardware.tv.input-V1.0-java-constants \
- android.hardware.usb-V1.0-java-constants \
- android.hardware.usb-V1.1-java-constants \
- android.hardware.vibrator-V1.0-java-constants \
- android.hardware.vibrator-V1.1-java-constants \
- android.hardware.wifi-V1.0-java-constants \
-
-# Loaded with System.loadLibrary by android.view.textclassifier
-LOCAL_REQUIRED_MODULES += libtextclassifier
-
-LOCAL_PROTOC_OPTIMIZE_TYPE := stream
-LOCAL_PROTOC_FLAGS := \
- -Iexternal/protobuf/src
-
-LOCAL_MODULE := framework
-
-LOCAL_JAVAC_SHARD_SIZE := 150
-
-LOCAL_DX_FLAGS := --core-library --multi-dex
-LOCAL_JACK_FLAGS := --multi-dex native
-
-LOCAL_RMTYPEDEFS := true
-
-ifeq ($(EMMA_INSTRUMENT_FRAMEWORK),true)
-LOCAL_EMMA_INSTRUMENT := true
-endif
-
-include $(BUILD_JAVA_LIBRARY)
-
-framework_module := $(LOCAL_INSTALLED_MODULE)
-$(framework_module): | $(dir $(framework_module))framework-res.apk
-
-framework_built := $(call java-lib-deps,framework)
-
# Copy AIDL files to be preprocessed and included in the SDK,
# specified relative to the root of the build tree.
# ============================================================
@@ -694,6 +46,7 @@
frameworks/base/telephony/java/android/telephony/NeighboringCellInfo.aidl \
frameworks/base/telephony/java/android/telephony/ModemActivityInfo.aidl \
frameworks/base/telephony/java/android/telephony/UiccAccessRule.aidl \
+ frameworks/base/telephony/java/android/telephony/data/DataCallResponse.aidl \
frameworks/base/telephony/java/android/telephony/data/DataProfile.aidl \
frameworks/base/telephony/java/android/telephony/euicc/DownloadableSubscription.aidl \
frameworks/base/telephony/java/android/telephony/euicc/EuiccInfo.aidl \
@@ -743,6 +96,7 @@
frameworks/base/core/java/android/app/admin/NetworkEvent.aidl \
frameworks/base/core/java/android/app/admin/SystemUpdatePolicy.aidl \
frameworks/base/core/java/android/app/admin/PasswordMetrics.aidl \
+ frameworks/base/core/java/android/app/slice/ISliceManager.aidl \
frameworks/base/core/java/android/print/PrintDocumentInfo.aidl \
frameworks/base/core/java/android/print/PageRange.aidl \
frameworks/base/core/java/android/print/PrintAttributes.aidl \
@@ -905,85 +259,78 @@
# TODO: deal with com/google/android/googleapps
packages_to_document := \
- android \
- javax/microedition/khronos \
- org/apache/http/conn \
- org/apache/http/params
-
-
-# Search through the base framework dirs for these packages.
-# The result will be relative to frameworks/base.
-fwbase_dirs_to_document := \
- legacy-test/src \
- $(patsubst $(LOCAL_PATH)/%,%, \
- $(wildcard \
- $(foreach dir, $(FRAMEWORKS_BASE_JAVA_SRC_DIRS), \
- $(addprefix $(dir)/, $(packages_to_document)) \
- ) \
- ) \
- )
+ android \
+ javax/microedition/khronos \
+ org/apache/http/conn \
+ org/apache/http/params \
# include definition of libcore_to_document
include libcore/Docs.mk
non_base_dirs := \
- ../opt/telephony/src/java/android/telephony \
- ../opt/telephony/src/java/android/telephony/gsm \
- ../opt/net/voip/src/java/android/net/rtp \
- ../opt/net/voip/src/java/android/net/sip
+ ../opt/telephony/src/java/android/telephony \
+ ../opt/telephony/src/java/android/telephony/gsm \
+ ../opt/net/voip/src/java/android/net/rtp \
+ ../opt/net/voip/src/java/android/net/sip \
framework_base_android_test_mock_src_files := \
- $(call all-java-files-under, test-mock/src/android/test/mock)
+ $(call all-java-files-under, test-mock/src/android/test/mock)
framework_base_android_test_runner_excluding_mock_src_files := \
- $(filter-out $(framework_base_android_test_mock_src_files), $(call all-java-files-under, test-runner/src))
+ $(filter-out $(framework_base_android_test_mock_src_files), $(call all-java-files-under, test-runner/src))
-# These are relative to frameworks/base
-dirs_to_check_apis := \
- $(fwbase_dirs_to_document) \
- $(non_base_dirs)
+# Find all files in specific directories (relative to frameworks/base)
+# to document and check apis
+files_to_check_apis := \
+ $(call find-other-java-files, \
+ test-base/src \
+ $(non_base_dirs) \
+ )
-###########################################################
-## Return all directories that have a 'NO_DOCS' file in
-## them, appending a '%' to them to form a pattern to
-## filter out files under those directories.
-## $(1): A list of base directories to look at.
-###########################################################
-define find-no-docs-pattern
-$(addsuffix %, $(dir $(foreach dir, $(1), $(shell cd $(LOCAL_PATH); find $(dir) -name NO_DOCS))))
-endef
+# Find all files in specific packages that were used to compile
+# framework.jar to document and check apis
+files_to_check_apis += \
+ $(addprefix ../../,\
+ $(filter \
+ $(foreach dir,$(FRAMEWORKS_BASE_JAVA_SRC_DIRS),\
+ $(foreach package,$(packages_to_document),\
+ $(dir)/$(package)/%.java)),\
+ $(SOONG_FRAMEWORK_SRCS)))
+
+# Find all generated files that were used to compile framework.jar
+files_to_check_apis_generated := \
+ $(filter $(OUT_DIR)/%,\
+ $(SOONG_FRAMEWORK_SRCS))
# These are relative to frameworks/base
# FRAMEWORKS_BASE_SUBDIRS comes from build/core/pathmap.mk
-dirs_to_document := \
- $(dirs_to_check_apis) \
- test-runner/src \
- $(addprefix ../../, $(FRAMEWORKS_DATA_BINDING_JAVA_SRC_DIRS))
-
-patterns_to_not_document := \
- $(call find-no-docs-pattern, $(dirs_to_document))
+files_to_document := \
+ $(files_to_check_apis) \
+ $(call find-other-java-files,\
+ $(addprefix ../../, $(FRAMEWORKS_DATA_BINDING_JAVA_SRC_DIRS)) \
+ test-runner/src)
# These are relative to frameworks/base
html_dirs := \
$(FRAMEWORKS_BASE_SUBDIRS) \
- $(non_base_dirs)
+ $(non_base_dirs) \
# Common sources for doc check and api check
common_src_files := \
$(call find-other-html-files, $(html_dirs)) \
- $(addprefix ../../, $(libcore_to_document))
+ $(addprefix ../../, $(libcore_to_document)) \
# These are relative to frameworks/base
framework_docs_LOCAL_SRC_FILES := \
- $(filter-out $(patterns_to_not_document), $(call find-other-java-files, $(dirs_to_document))) \
- $(common_src_files)
+ $(files_to_document) \
+ $(common_src_files) \
# These are relative to frameworks/base
framework_docs_LOCAL_API_CHECK_SRC_FILES := \
- $(framework_base_android_test_mock_src_files) \
- $(framework_base_android_test_runner_excluding_mock_src_files) \
- $(call all-java-files-under, $(dirs_to_check_apis)) \
- $(common_src_files)
+ $(framework_base_android_test_mock_src_files) \
+ $(framework_base_android_test_runner_excluding_mock_src_files) \
+ $(files_to_check_apis) \
+ $(common_src_files) \
# This is used by ide.mk as the list of source files that are
# always included.
@@ -992,11 +339,11 @@
framework_docs_LOCAL_DROIDDOC_SOURCE_PATH := \
$(FRAMEWORKS_BASE_JAVA_SRC_DIRS)
-framework_docs_LOCAL_INTERMEDIATE_SOURCES := \
- $(framework_res_source_path)/android/R.java \
- $(framework_res_source_path)/android/Manifest.java \
- $(framework_res_source_path)/com/android/internal/R.java \
- $(patsubst $(TARGET_OUT_COMMON_INTERMEDIATES)/%,%,$(libcore_to_document_generated))
+framework_docs_LOCAL_SRCJARS := $(SOONG_FRAMEWORK_SRCJARS)
+
+framework_docs_LOCAL_GENERATED_SOURCES := \
+ $(libcore_to_document_generated) \
+ $(files_to_check_apis_generated) \
framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES := \
core-oj \
@@ -1058,7 +405,7 @@
-since $(SRC_API_DIR)/25.txt 25 \
-since $(SRC_API_DIR)/26.txt 26 \
-since $(SRC_API_DIR)/27.txt 27 \
- -werror -lerror -hide 111 -hide 113 -hide 121 -hide 125 -hide 126 -hide 127 -hide 128 \
+ -werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 \
-overview $(LOCAL_PATH)/core/java/overview.html \
framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR:= \
@@ -1113,11 +460,12 @@
-federate SupportLib https://developer.android.com \
-federationapi SupportLib prebuilts/sdk/current/support-api.txt
-# ==== the api diff ===========================
+# ==== Public API diff ===========================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(framework_docs_LOCAL_API_CHECK_SRC_FILES)
-LOCAL_INTERMEDIATE_SOURCES := $(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_GENERATED_SOURCES := $(framework_docs_LOCAL_GENERATED_SOURCES)
+LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
LOCAL_JAVA_LIBRARIES := $(framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES)
LOCAL_MODULE_CLASS := $(framework_docs_LOCAL_MODULE_CLASS)
LOCAL_ADDITIONAL_JAVA_DIR := $(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR)
@@ -1138,11 +486,38 @@
include $(BUILD_APIDIFF)
+# ==== System API diff ===========================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(framework_docs_LOCAL_API_CHECK_SRC_FILES)
+LOCAL_GENERATED_SOURCES := $(framework_docs_LOCAL_GENERATED_SOURCES)
+LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
+LOCAL_JAVA_LIBRARIES := $(framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES)
+LOCAL_MODULE_CLASS := $(framework_docs_LOCAL_MODULE_CLASS)
+LOCAL_ADDITIONAL_JAVA_DIR := $(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR)
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+ $(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES) \
+ $(INTERNAL_PLATFORM_SYSTEM_API_FILE)
+
+LOCAL_MODULE := offline-system-sdk-referenceonly
+
+last_released_sdk_version := $(lastword $(call numerically_sort, \
+ $(filter-out current, \
+ $(patsubst $(SRC_SYSTEM_API_DIR)/%.txt,%, $(wildcard $(SRC_SYSTEM_API_DIR)/*.txt)) \
+ )\
+ ))
+
+LOCAL_APIDIFF_OLDAPI := $(LOCAL_PATH)/../../$(SRC_SYSTEM_API_DIR)/$(last_released_sdk_version)
+LOCAL_APIDIFF_NEWAPI := $(LOCAL_PATH)/../../$(basename $(INTERNAL_PLATFORM_SYSTEM_API_FILE))
+
+include $(BUILD_APIDIFF)
+
# ==== the api stubs and current.xml ===========================
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=$(framework_docs_LOCAL_API_CHECK_SRC_FILES)
-LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_GENERATED_SOURCES:=$(framework_docs_LOCAL_GENERATED_SOURCES)
+LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES)
LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
@@ -1168,7 +543,7 @@
include $(BUILD_DROIDDOC)
# $(gen), i.e. framework.aidl, is also needed while building against the current stub.
-$(full_target): $(framework_built) $(gen)
+$(full_target): $(gen)
$(INTERNAL_PLATFORM_API_FILE): $(full_target)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
@@ -1176,7 +551,8 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=$(framework_docs_LOCAL_API_CHECK_SRC_FILES)
-LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_GENERATED_SOURCES:=$(framework_docs_LOCAL_GENERATED_SOURCES)
+LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES)
LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
@@ -1204,7 +580,7 @@
include $(BUILD_DROIDDOC)
# $(gen), i.e. framework.aidl, is also needed while building against the current stub.
-$(full_target): $(framework_built) $(gen)
+$(full_target): $(gen)
$(INTERNAL_PLATFORM_SYSTEM_API_FILE): $(full_target)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_API_FILE))
@@ -1212,7 +588,8 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=$(framework_docs_LOCAL_API_CHECK_SRC_FILES)
-LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_GENERATED_SOURCES:=$(framework_docs_LOCAL_GENERATED_SOURCES)
+LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES)
LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
@@ -1241,7 +618,7 @@
include $(BUILD_DROIDDOC)
# $(gen), i.e. framework.aidl, is also needed while building against the current stub.
-$(full_target): $(framework_built) $(gen)
+$(full_target): $(gen)
$(INTERNAL_PLATFORM_TEST_API_FILE): $(full_target)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_TEST_API_FILE))
@@ -1249,7 +626,8 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
-LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_GENERATED_SOURCES:=$(framework_docs_LOCAL_GENERATED_SOURCES)
+LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
@@ -1271,18 +649,23 @@
include $(BUILD_DROIDDOC)
# $(gen), i.e. framework.aidl, is also needed while building against the current stub.
-$(full_target): $(framework_built) $(gen)
+$(full_target): $(gen)
# Run this for checkbuild
checkbuild: doc-comment-check-docs
# Check comment when you are updating the API
update-api: doc-comment-check-docs
+# Generate API diffs as part of docs builds
+docs: offline-sdk-referenceonly-diff
+docs: offline-system-sdk-referenceonly-diff
+
# ==== static html in the sdk ==================================
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
-LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_GENERATED_SOURCES:=$(framework_docs_LOCAL_GENERATED_SOURCES)
+LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
@@ -1311,14 +694,14 @@
$(hide) $(ACP) $< $@
$(full_target): $(static_doc_index_redirect)
-$(full_target): $(framework_built)
-# ==== static html in the sdk ==================================
+# ==== Public API static reference docs ==================================
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
-LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_GENERATED_SOURCES:=$(framework_docs_LOCAL_GENERATED_SOURCES)
+LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
@@ -1353,6 +736,50 @@
$(full_target): $(static_doc_index_redirect)
$(full_target): $(static_doc_properties)
+
+
+# ==== System API static reference docs ==================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
+LOCAL_GENERATED_SOURCES:=$(framework_docs_LOCAL_GENERATED_SOURCES)
+LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
+LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
+LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
+LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
+LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
+LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
+LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
+
+LOCAL_MODULE := offline-system-sdk-referenceonly
+
+LOCAL_DROIDDOC_OPTIONS:=\
+ $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+ -hide 101 -hide 104 -hide 108 \
+ -showAnnotation android.annotation.SystemApi \
+ -offlinemode \
+ -title "Android System SDK" \
+ -proofread $(OUT_DOCS)/$(LOCAL_MODULE)-proofread.txt \
+ -sdkvalues $(OUT_DOCS) \
+ -hdf android.whichdoc offline \
+ -referenceonly
+
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
+
+include $(BUILD_DROIDDOC)
+
+static_doc_index_redirect := $(out_dir)/index.html
+$(static_doc_index_redirect): $(LOCAL_PATH)/docs/docs-documentation-redirect.html
+ $(copy-file-to-target)
+
+static_doc_properties := $(out_dir)/source.properties
+$(static_doc_properties): \
+ $(LOCAL_PATH)/docs/source.properties | $(ACP)
+ $(hide) mkdir -p $(dir $@)
+ $(hide) $(ACP) $< $@
+
+$(full_target): $(static_doc_index_redirect)
+$(full_target): $(static_doc_properties)
$(full_target): $(framework_built)
@@ -1360,7 +787,8 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
-LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_GENERATED_SOURCES:=$(framework_docs_LOCAL_GENERATED_SOURCES)
+LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
LOCAL_STATIC_JAVA_LIBRARIES:=$(framework_docs_LOCAL_STATIC_JAVA_LIBRARIES)
LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
@@ -1388,7 +816,8 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
-LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_GENERATED_SOURCES:=$(framework_docs_LOCAL_GENERATED_SOURCES)
+LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
LOCAL_STATIC_JAVA_LIBRARIES:=$(framework_docs_LOCAL_STATIC_JAVA_LIBRARIES)
LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
@@ -1423,7 +852,8 @@
# ==== docs for the web (on the devsite app engine server) =======================
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
-LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_GENERATED_SOURCES:=$(framework_docs_LOCAL_GENERATED_SOURCES)
+LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
LOCAL_STATIC_JAVA_LIBRARIES:=$(framework_docs_LOCAL_STATIC_JAVA_LIBRARIES)
LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
@@ -1452,7 +882,8 @@
# ==== docs for the web (on the devsite app engine server) =======================
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
-LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_GENERATED_SOURCES:=$(framework_docs_LOCAL_GENERATED_SOURCES)
+LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
LOCAL_STATIC_JAVA_LIBRARIES:=$(framework_docs_LOCAL_STATIC_JAVA_LIBRARIES)
LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
@@ -1481,7 +912,8 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
-LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_GENERATED_SOURCES:=$(framework_docs_LOCAL_GENERATED_SOURCES)
+LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
LOCAL_STATIC_JAVA_LIBRARIES:=$(framework_docs_LOCAL_STATIC_JAVA_LIBRARIES)
LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
@@ -1506,7 +938,8 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
-LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_GENERATED_SOURCES:=$(framework_docs_LOCAL_GENERATED_SOURCES)
+LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
LOCAL_STATIC_JAVA_LIBRARIES:=$(framework_docs_LOCAL_STATIC_JAVA_LIBRARIES)
LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
@@ -1534,7 +967,8 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
-LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_GENERATED_SOURCES:=$(framework_docs_LOCAL_GENERATED_SOURCES)
+LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/PaintMeasureTextTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/PaintMeasureTextTest.java
index b81908c..b9ee613 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/PaintMeasureTextTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/PaintMeasureTextTest.java
@@ -80,11 +80,11 @@
}
while (state.keepRunning()) {
- state.pauseTiming();
if (mCacheMode == DONT_USE_CACHE) {
+ state.pauseTiming();
Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
}
- state.resumeTiming();
paint.measureText(mText);
}
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
index 57a61ec..92ee7cc 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
@@ -22,6 +22,11 @@
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
+import android.content.res.ColorStateList;
+import android.graphics.Typeface;
+import android.text.Layout;
+import android.text.style.TextAppearanceSpan;
+
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -33,40 +38,35 @@
@RunWith(AndroidJUnit4.class)
public class StaticLayoutPerfTest {
- public StaticLayoutPerfTest() {
- }
+ public StaticLayoutPerfTest() {}
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
- private static final String FIXED_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing "
- + "elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad "
- + "minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
- + "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse "
- + "cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non "
- + "proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
- private static final int FIXED_TEXT_LENGTH = FIXED_TEXT.length();
+ private static final int WORD_LENGTH = 9; // Random word has 9 characters.
+ private static final int WORDS_IN_LINE = 8; // Roughly, 8 words in a line.
+ private static final int PARA_LENGTH = 500; // Number of characters in a paragraph.
- private static TextPaint PAINT = new TextPaint();
- private static final int TEXT_WIDTH = 20 * (int) PAINT.getTextSize();
+ private static final boolean NO_STYLE_TEXT = false;
+ private static final boolean STYLE_TEXT = true;
- @Test
- public void testCreate() {
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- while (state.keepRunning()) {
- StaticLayout.Builder.obtain(FIXED_TEXT, 0, FIXED_TEXT_LENGTH, PAINT, TEXT_WIDTH)
- .build();
- }
- }
+ private final Random mRandom = new Random(31415926535L);
private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
private static final int ALPHABET_LENGTH = ALPHABET.length();
- private static final int PARA_LENGTH = 500;
- private final char[] mBuffer = new char[PARA_LENGTH];
- private final Random mRandom = new Random(31415926535L);
+ private static final ColorStateList TEXT_COLOR = ColorStateList.valueOf(0x00000000);
+ private static final String[] FAMILIES = { "sans-serif", "serif", "monospace" };
+ private static final int[] STYLES = {
+ Typeface.NORMAL, Typeface.BOLD, Typeface.ITALIC, Typeface.BOLD_ITALIC
+ };
- private CharSequence generateRandomParagraph(int wordLen) {
+ private final char[] mBuffer = new char[PARA_LENGTH];
+
+ private static TextPaint PAINT = new TextPaint();
+ private static final int TEXT_WIDTH = WORDS_IN_LINE * WORD_LENGTH * (int) PAINT.getTextSize();
+
+ private CharSequence generateRandomParagraph(int wordLen, boolean applyRandomStyle) {
for (int i = 0; i < PARA_LENGTH; i++) {
if (i % (wordLen + 1) == wordLen) {
mBuffer[i] = ' ';
@@ -74,29 +74,112 @@
mBuffer[i] = ALPHABET.charAt(mRandom.nextInt(ALPHABET_LENGTH));
}
}
- return CharBuffer.wrap(mBuffer);
+
+ CharSequence cs = CharBuffer.wrap(mBuffer);
+ if (!applyRandomStyle) {
+ return cs;
+ }
+
+ SpannableStringBuilder ssb = new SpannableStringBuilder(cs);
+ for (int i = 0; i < ssb.length(); i += WORD_LENGTH) {
+ final int spanStart = i;
+ final int spanEnd = (i + WORD_LENGTH) > ssb.length() ? ssb.length() : i + WORD_LENGTH;
+
+ final TextAppearanceSpan span = new TextAppearanceSpan(
+ FAMILIES[mRandom.nextInt(FAMILIES.length)],
+ STYLES[mRandom.nextInt(STYLES.length)],
+ 24 + mRandom.nextInt(32), // text size. min 24 max 56
+ TEXT_COLOR, TEXT_COLOR);
+
+ ssb.setSpan(span, spanStart, spanEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+ }
+ return ssb;
}
- // This tries to simulate the case where the cache hit rate is low, and most of the text is
- // new text.
@Test
- public void testCreateRandom() {
+ public void testCreate_FixedText_NoStyle_Greedy_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
while (state.keepRunning()) {
- final CharSequence text = generateRandomParagraph(9);
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.build();
}
}
@Test
- public void testCreateRandom_breakBalanced() {
+ public void testCreate_RandomText_NoStyled_Greedy_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
- final CharSequence text = generateRandomParagraph(9);
+ state.pauseTiming();
+ final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+ state.resumeTiming();
+
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
+ .build();
+ }
+ }
+
+ @Test
+ public void testCreate_RandomText_NoStyled_Greedy_Hyphenation() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+ state.resumeTiming();
+
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
+ .build();
+ }
+ }
+
+ @Test
+ public void testCreate_RandomText_NoStyled_Balanced_NoHyphenation() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+ state.resumeTiming();
+
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
.build();
}
}
+
+ @Test
+ public void testCreate_RandomText_NoStyled_Balanced_Hyphenation() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+ state.resumeTiming();
+
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
+ .build();
+ }
+ }
+
+ @Test
+ public void testCreate_RandomText_Styled_Greedy_NoHyphenation() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final CharSequence text = generateRandomParagraph(WORD_LENGTH, STYLE_TEXT);
+ state.resumeTiming();
+
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
+ .build();
+ }
+ }
}
diff --git a/api/current.txt b/api/current.txt
index 93b6b42..f56f1a1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -343,6 +343,7 @@
field public static final int buttonBarNeutralButtonStyle = 16843914; // 0x101048a
field public static final int buttonBarPositiveButtonStyle = 16843913; // 0x1010489
field public static final int buttonBarStyle = 16843566; // 0x101032e
+ field public static final int buttonCornerRadius = 16844149; // 0x1010575
field public static final int buttonGravity = 16844030; // 0x10104fe
field public static final int buttonStyle = 16842824; // 0x1010048
field public static final int buttonStyleInset = 16842826; // 0x101004a
@@ -1119,6 +1120,7 @@
field public static final int scheme = 16842791; // 0x1010027
field public static final int screenDensity = 16843467; // 0x10102cb
field public static final int screenOrientation = 16842782; // 0x101001e
+ field public static final int screenReaderFocusable = 16844148; // 0x1010574
field public static final int screenSize = 16843466; // 0x10102ca
field public static final int scrollHorizontally = 16843099; // 0x101015b
field public static final int scrollIndicators = 16844006; // 0x10104e6
@@ -1468,6 +1470,8 @@
field public static final int vendor = 16843751; // 0x10103e7
field public static final int version = 16844057; // 0x1010519
field public static final int versionCode = 16843291; // 0x101021b
+ field public static final int versionCodeMajor = 16844150; // 0x1010576
+ field public static final int versionMajor = 16844151; // 0x1010577
field public static final int versionName = 16843292; // 0x101021c
field public static final int verticalCorrection = 16843322; // 0x101023a
field public static final int verticalDivider = 16843054; // 0x101012e
@@ -1501,6 +1505,7 @@
field public static final deprecated int weekSeparatorLineColor = 16843590; // 0x1010346
field public static final int weightSum = 16843048; // 0x1010128
field public static final int widgetCategory = 16843716; // 0x10103c4
+ field public static final int widgetFeatures = 16844153; // 0x1010579
field public static final int widgetLayout = 16843243; // 0x10101eb
field public static final int width = 16843097; // 0x1010159
field public static final int windowActionBar = 16843469; // 0x10102cd
@@ -2313,7 +2318,9 @@
field public static final int Widget_DeviceDefault_AutoCompleteTextView = 16974151; // 0x1030147
field public static final int Widget_DeviceDefault_Button = 16974145; // 0x1030141
field public static final int Widget_DeviceDefault_Button_Borderless = 16974188; // 0x103016c
+ field public static final int Widget_DeviceDefault_Button_Borderless_Colored = 16974561; // 0x10302e1
field public static final int Widget_DeviceDefault_Button_Borderless_Small = 16974149; // 0x1030145
+ field public static final int Widget_DeviceDefault_Button_Colored = 16974560; // 0x10302e0
field public static final int Widget_DeviceDefault_Button_Inset = 16974147; // 0x1030143
field public static final int Widget_DeviceDefault_Button_Small = 16974146; // 0x1030142
field public static final int Widget_DeviceDefault_Button_Toggle = 16974148; // 0x1030144
@@ -4988,7 +4995,7 @@
public class KeyguardManager {
method public android.content.Intent createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence);
method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
- method public boolean inKeyguardRestrictedInputMode();
+ method public deprecated boolean inKeyguardRestrictedInputMode();
method public boolean isDeviceLocked();
method public boolean isDeviceSecure();
method public boolean isKeyguardLocked();
@@ -6316,6 +6323,7 @@
method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
method public void enableSystemApp(android.content.ComponentName, java.lang.String);
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
+ method public android.security.AttestedKeyPair generateKeyPair(android.content.ComponentName, java.lang.String, android.security.keystore.KeyGenParameterSpec);
method public java.lang.String[] getAccountTypesWithManagementDisabled();
method public java.util.List<android.content.ComponentName> getActiveAdmins();
method public java.util.Set<java.lang.String> getAffiliationIds(android.content.ComponentName);
@@ -6364,6 +6372,7 @@
method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName);
method public long getRequiredStrongAuthTimeout(android.content.ComponentName);
method public boolean getScreenCaptureDisabled(android.content.ComponentName);
+ method public java.util.List<android.os.UserHandle> getSecondaryUsers(android.content.ComponentName);
method public java.lang.CharSequence getShortSupportMessage(android.content.ComponentName);
method public boolean getStorageEncryption(android.content.ComponentName);
method public int getStorageEncryptionStatus();
@@ -6384,6 +6393,7 @@
method public deprecated boolean isCallerApplicationRestrictionsManagingPackage();
method public boolean isDeviceOwnerApp(java.lang.String);
method public boolean isLockTaskPermitted(java.lang.String);
+ method public boolean isLogoutButtonEnabled();
method public boolean isManagedProfile(android.content.ComponentName);
method public boolean isMasterVolumeMuted(android.content.ComponentName);
method public boolean isNetworkLoggingEnabled(android.content.ComponentName);
@@ -6395,6 +6405,7 @@
method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
method public void lockNow();
method public void lockNow(int);
+ method public boolean logoutUser(android.content.ComponentName);
method public void reboot(android.content.ComponentName);
method public void removeActiveAdmin(android.content.ComponentName);
method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
@@ -6426,6 +6437,7 @@
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
method public void setLockTaskFeatures(android.content.ComponentName, int);
method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
+ method public void setLogoutButtonEnabled(android.content.ComponentName, boolean);
method public void setLongSupportMessage(android.content.ComponentName, java.lang.CharSequence);
method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
@@ -6461,12 +6473,14 @@
method public void setShortSupportMessage(android.content.ComponentName, java.lang.CharSequence);
method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
method public int setStorageEncryption(android.content.ComponentName, boolean);
+ method public void setSystemSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
method public boolean setTime(android.content.ComponentName, long);
method public boolean setTimeZone(android.content.ComponentName, java.lang.String);
method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
method public void setUserIcon(android.content.ComponentName, android.graphics.Bitmap);
+ method public boolean stopUser(android.content.ComponentName, android.os.UserHandle);
method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
method public void uninstallAllUserCaCerts(android.content.ComponentName);
method public void uninstallCaCert(android.content.ComponentName, byte[]);
@@ -6588,6 +6602,7 @@
public abstract class NetworkEvent implements android.os.Parcelable {
method public int describeContents();
+ method public long getId();
method public java.lang.String getPackageName();
method public long getTimestamp();
field public static final android.os.Parcelable.Creator<android.app.admin.NetworkEvent> CREATOR;
@@ -6761,6 +6776,7 @@
method public void onFullBackup(android.app.backup.FullBackupDataOutput) throws java.io.IOException;
method public void onQuotaExceeded(long, long);
method public abstract void onRestore(android.app.backup.BackupDataInput, int, android.os.ParcelFileDescriptor) throws java.io.IOException;
+ method public void onRestore(android.app.backup.BackupDataInput, long, android.os.ParcelFileDescriptor) throws java.io.IOException;
method public void onRestoreFile(android.os.ParcelFileDescriptor, long, java.io.File, int, long, long) throws java.io.IOException;
method public void onRestoreFinished();
field public static final int TYPE_DIRECTORY = 2; // 0x2
@@ -7204,6 +7220,7 @@
}
public final class UsageStatsManager {
+ method public int getAppStandbyBucket();
method public boolean isAppInactive(java.lang.String);
method public java.util.Map<java.lang.String, android.app.usage.UsageStats> queryAndAggregateUsageStats(long, long);
method public java.util.List<android.app.usage.ConfigurationStats> queryConfigurations(int, long, long);
@@ -7214,6 +7231,10 @@
field public static final int INTERVAL_MONTHLY = 2; // 0x2
field public static final int INTERVAL_WEEKLY = 1; // 0x1
field public static final int INTERVAL_YEARLY = 3; // 0x3
+ field public static final int STANDBY_BUCKET_ACTIVE = 10; // 0xa
+ field public static final int STANDBY_BUCKET_FREQUENT = 30; // 0x1e
+ field public static final int STANDBY_BUCKET_RARE = 40; // 0x28
+ field public static final int STANDBY_BUCKET_WORKING_SET = 20; // 0x14
}
}
@@ -7332,6 +7353,8 @@
field public static final int WIDGET_CATEGORY_HOME_SCREEN = 1; // 0x1
field public static final int WIDGET_CATEGORY_KEYGUARD = 2; // 0x2
field public static final int WIDGET_CATEGORY_SEARCHBOX = 4; // 0x4
+ field public static final int WIDGET_FEATURE_HIDE_FROM_PICKER = 2; // 0x2
+ field public static final int WIDGET_FEATURE_RECONFIGURABLE = 1; // 0x1
field public int autoAdvanceViewId;
field public android.content.ComponentName configure;
field public int icon;
@@ -7347,6 +7370,7 @@
field public int resizeMode;
field public int updatePeriodMillis;
field public int widgetCategory;
+ field public int widgetFeatures;
}
}
@@ -9950,6 +9974,7 @@
}
public class QuickViewConstants {
+ field public static final java.lang.String FEATURE_DELETE = "android:delete";
field public static final java.lang.String FEATURE_DOWNLOAD = "android:download";
field public static final java.lang.String FEATURE_EDIT = "android:edit";
field public static final java.lang.String FEATURE_PRINT = "android:print";
@@ -10061,6 +10086,7 @@
public abstract interface ServiceConnection {
method public default void onBindingDied(android.content.ComponentName);
+ method public default void onNullBinding(android.content.ComponentName);
method public abstract void onServiceConnected(android.content.ComponentName, android.os.IBinder);
method public abstract void onServiceDisconnected(android.content.ComponentName);
}
@@ -10579,6 +10605,8 @@
public class PackageInfo implements android.os.Parcelable {
ctor public PackageInfo();
method public int describeContents();
+ method public long getLongVersionCode();
+ method public void setLongVersionCode(long);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.PackageInfo> CREATOR;
field public static final int INSTALL_LOCATION_AUTO = 0; // 0x0
@@ -10608,7 +10636,7 @@
field public android.content.pm.Signature[] signatures;
field public java.lang.String[] splitNames;
field public int[] splitRevisionCodes;
- field public int versionCode;
+ field public deprecated int versionCode;
field public java.lang.String versionName;
}
@@ -11123,9 +11151,10 @@
method public int describeContents();
method public android.content.pm.VersionedPackage getDeclaringPackage();
method public java.util.List<android.content.pm.VersionedPackage> getDependentPackages();
+ method public long getLongVersion();
method public java.lang.String getName();
method public int getType();
- method public int getVersion();
+ method public deprecated int getVersion();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.SharedLibraryInfo> CREATOR;
field public static final int TYPE_BUILTIN = 0; // 0x0
@@ -11219,9 +11248,11 @@
public final class VersionedPackage implements android.os.Parcelable {
ctor public VersionedPackage(java.lang.String, int);
+ ctor public VersionedPackage(java.lang.String, long);
method public int describeContents();
+ method public long getLongVersionCode();
method public java.lang.String getPackageName();
- method public int getVersionCode();
+ method public deprecated int getVersionCode();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.VersionedPackage> CREATOR;
}
@@ -11231,6 +11262,8 @@
package android.content.pm.crossprofile {
public class CrossProfileApps {
+ method public android.graphics.drawable.Drawable getProfileSwitchingIcon(android.os.UserHandle);
+ method public java.lang.CharSequence getProfileSwitchingLabel(android.os.UserHandle);
method public java.util.List<android.os.UserHandle> getTargetUserProfiles();
method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
}
@@ -15483,6 +15516,8 @@
field public static final int CONTROL_AF_MODE_EDOF = 5; // 0x5
field public static final int CONTROL_AF_MODE_MACRO = 2; // 0x2
field public static final int CONTROL_AF_MODE_OFF = 0; // 0x0
+ field public static final int CONTROL_AF_SCENE_CHANGE_DETECTED = 1; // 0x1
+ field public static final int CONTROL_AF_SCENE_CHANGE_NOT_DETECTED = 0; // 0x0
field public static final int CONTROL_AF_STATE_ACTIVE_SCAN = 3; // 0x3
field public static final int CONTROL_AF_STATE_FOCUSED_LOCKED = 4; // 0x4
field public static final int CONTROL_AF_STATE_INACTIVE = 0; // 0x0
@@ -15757,6 +15792,7 @@
field public static final android.hardware.camera2.CaptureResult.Key<android.util.Range<java.lang.Integer>> CONTROL_AE_TARGET_FPS_RANGE;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AF_MODE;
field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AF_REGIONS;
+ field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AF_SCENE_CHANGE;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AF_STATE;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AF_TRIGGER;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Boolean> CONTROL_AWB_LOCK;
@@ -22028,6 +22064,7 @@
method public android.media.Image acquireLatestImage();
method public android.media.Image acquireNextImage();
method public void close();
+ method public void discardFreeBuffers();
method public int getHeight();
method public int getImageFormat();
method public int getMaxImages();
@@ -23252,16 +23289,20 @@
field public static final int MEDIA_TRACK_TYPE_VIDEO = 1; // 0x1
}
- public class MediaRecorder {
+ public class MediaRecorder implements android.media.AudioRouting {
ctor public MediaRecorder();
+ method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method protected void finalize();
method public static final int getAudioSourceMax();
method public int getMaxAmplitude() throws java.lang.IllegalStateException;
method public android.os.PersistableBundle getMetrics();
+ method public android.media.AudioDeviceInfo getPreferredDevice();
+ method public android.media.AudioDeviceInfo getRoutedDevice();
method public android.view.Surface getSurface();
method public void pause() throws java.lang.IllegalStateException;
method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
method public void release();
+ method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public void reset();
method public void resume() throws java.lang.IllegalStateException;
method public void setAudioChannels(int);
@@ -23284,6 +23325,7 @@
method public void setOutputFile(java.io.File);
method public void setOutputFile(java.lang.String) throws java.lang.IllegalStateException;
method public void setOutputFormat(int) throws java.lang.IllegalStateException;
+ method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
method public void setPreviewDisplay(android.view.Surface);
method public void setProfile(android.media.CamcorderProfile);
method public void setVideoEncoder(int) throws java.lang.IllegalStateException;
@@ -25958,6 +26000,23 @@
enum_constant public static final android.net.LocalSocketAddress.Namespace RESERVED;
}
+ public final class MacAddress implements android.os.Parcelable {
+ method public int addressType();
+ method public int describeContents();
+ method public static android.net.MacAddress fromBytes(byte[]);
+ method public static android.net.MacAddress fromString(java.lang.String);
+ method public boolean isLocallyAssigned();
+ method public byte[] toByteArray();
+ method public java.lang.String toSafeString();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.net.MacAddress BROADCAST_ADDRESS;
+ field public static final android.os.Parcelable.Creator<android.net.MacAddress> CREATOR;
+ field public static final int TYPE_BROADCAST = 3; // 0x3
+ field public static final int TYPE_MULTICAST = 2; // 0x2
+ field public static final int TYPE_UNICAST = 1; // 0x1
+ field public static final int TYPE_UNKNOWN = 0; // 0x0
+ }
+
public class MailTo {
method public java.lang.String getBody();
method public java.lang.String getCc();
@@ -26155,6 +26214,7 @@
public class TrafficStats {
ctor public TrafficStats();
method public static void clearThreadStatsTag();
+ method public static void clearThreadStatsUid();
method public static int getAndSetThreadStatsTag(int);
method public static long getMobileRxBytes();
method public static long getMobileRxPackets();
@@ -26180,9 +26240,12 @@
method public static void incrementOperationCount(int);
method public static void incrementOperationCount(int, int);
method public static void setThreadStatsTag(int);
+ method public static void setThreadStatsUidSelf();
method public static void tagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+ method public static void tagFileDescriptor(java.io.FileDescriptor) throws java.io.IOException;
method public static void tagSocket(java.net.Socket) throws java.net.SocketException;
method public static void untagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+ method public static void untagFileDescriptor(java.io.FileDescriptor) throws java.io.IOException;
method public static void untagSocket(java.net.Socket) throws java.net.SocketException;
field public static final int UNSUPPORTED = -1; // 0xffffffff
}
@@ -33129,6 +33192,7 @@
public final class AlarmClock {
ctor public AlarmClock();
field public static final java.lang.String ACTION_DISMISS_ALARM = "android.intent.action.DISMISS_ALARM";
+ field public static final java.lang.String ACTION_DISMISS_TIMER = "android.intent.action.DISMISS_TIMER";
field public static final java.lang.String ACTION_SET_ALARM = "android.intent.action.SET_ALARM";
field public static final java.lang.String ACTION_SET_TIMER = "android.intent.action.SET_TIMER";
field public static final java.lang.String ACTION_SHOW_ALARMS = "android.intent.action.SHOW_ALARMS";
@@ -34279,6 +34343,8 @@
field public static final java.lang.String IS_READ_ONLY = "is_read_only";
field public static final java.lang.String IS_SUPER_PRIMARY = "is_super_primary";
field public static final java.lang.String MIMETYPE = "mimetype";
+ field public static final java.lang.String PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME = "preferred_phone_account_component_name";
+ field public static final java.lang.String PREFERRED_PHONE_ACCOUNT_ID = "preferred_phone_account_id";
field public static final java.lang.String RAW_CONTACT_ID = "raw_contact_id";
field public static final java.lang.String RES_PACKAGE = "res_package";
field public static final java.lang.String SYNC1 = "data_sync1";
@@ -35945,6 +36011,7 @@
field public static final java.lang.String DATE = "date";
field public static final java.lang.String DELETED = "deleted";
field public static final java.lang.String DIRTY = "dirty";
+ field public static final int DIRTY_RETAIN = -1; // 0xffffffff
field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemails";
field public static final java.lang.String DURATION = "duration";
field public static final java.lang.String HAS_CONTENT = "has_content";
@@ -37084,6 +37151,11 @@
package android.security {
+ public final class AttestedKeyPair {
+ method public java.util.List<java.security.cert.Certificate> getAttestationRecord();
+ method public java.security.KeyPair getKeyPair();
+ }
+
public final class KeyChain {
ctor public KeyChain();
method public static void choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, java.lang.String[], java.security.Principal[], java.lang.String, int, java.lang.String);
@@ -37461,6 +37533,8 @@
method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle);
method public android.service.autofill.FillResponse.Builder setFlags(int);
+ method public android.service.autofill.FillResponse.Builder setFooter(android.widget.RemoteViews);
+ method public android.service.autofill.FillResponse.Builder setHeader(android.widget.RemoteViews);
method public android.service.autofill.FillResponse.Builder setIgnoredIds(android.view.autofill.AutofillId...);
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
@@ -37556,6 +37630,7 @@
public final class Validators {
method public static android.service.autofill.Validator and(android.service.autofill.Validator...);
+ method public static android.service.autofill.Validator not(android.service.autofill.Validator);
method public static android.service.autofill.Validator or(android.service.autofill.Validator...);
}
@@ -39260,6 +39335,7 @@
field public static final int HANDOVER_FAILURE_DEST_INVALID_PERM = 3; // 0x3
field public static final int HANDOVER_FAILURE_DEST_NOT_SUPPORTED = 2; // 0x2
field public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4; // 0x4
+ field public static final int HANDOVER_FAILURE_ONGOING_EMERG_CALL = 5; // 0x5
}
public static class Call.Details {
@@ -39439,6 +39515,7 @@
method public final int getState();
method public final android.telecom.StatusHints getStatusHints();
method public final android.telecom.Connection.VideoProvider getVideoProvider();
+ method public void handleRttUpgradeResponse(android.telecom.Connection.RttTextStream);
method public final boolean isRingbackRequested();
method public void onAbort();
method public void onAnswer(int);
@@ -39455,8 +39532,10 @@
method public void onReject(java.lang.String);
method public void onSeparate();
method public void onShowIncomingCallUi();
+ method public void onStartRtt(android.telecom.Connection.RttTextStream);
method public void onStateChanged(int);
method public void onStopDtmfTone();
+ method public void onStopRtt();
method public void onUnhold();
method public static java.lang.String propertiesToString(int);
method public final void putExtras(android.os.Bundle);
@@ -39464,6 +39543,10 @@
method public final void removeExtras(java.lang.String...);
method public void requestBluetoothAudio(java.lang.String);
method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
+ method public final void sendRemoteRttRequest();
+ method public final void sendRttInitiationFailure(int);
+ method public final void sendRttInitiationSuccess();
+ method public final void sendRttSessionRemotelyTerminated();
method public final void setActive();
method public final void setAddress(android.net.Uri, int);
method public final void setAudioModeIsVoip(boolean);
@@ -39517,6 +39600,7 @@
field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
+ field public static final int PROPERTY_IS_RTT = 256; // 0x100
field public static final int PROPERTY_SELF_MANAGED = 128; // 0x80
field public static final int STATE_ACTIVE = 4; // 0x4
field public static final int STATE_DIALING = 3; // 0x3
@@ -39536,6 +39620,12 @@
field public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4; // 0x4
}
+ public static final class Connection.RttTextStream {
+ method public java.lang.String read() throws java.io.IOException;
+ method public java.lang.String readImmediately() throws java.io.IOException;
+ method public void write(java.lang.String) throws java.io.IOException;
+ }
+
public static abstract class Connection.VideoProvider {
ctor public Connection.VideoProvider();
method public void changeCameraCapabilities(android.telecom.VideoProfile.CameraCapabilities);
@@ -39576,7 +39666,9 @@
method public android.telecom.PhoneAccountHandle getAccountHandle();
method public android.net.Uri getAddress();
method public android.os.Bundle getExtras();
+ method public android.telecom.Connection.RttTextStream getRttTextStream();
method public int getVideoState();
+ method public boolean isRequestingRtt();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telecom.ConnectionRequest> CREATOR;
}
@@ -39586,12 +39678,15 @@
method public final void addConference(android.telecom.Conference);
method public final void addExistingConnection(android.telecom.PhoneAccountHandle, android.telecom.Connection);
method public final void conferenceRemoteConnections(android.telecom.RemoteConnection, android.telecom.RemoteConnection);
+ method public final void connectionServiceFocusReleased();
method public final android.telecom.RemoteConnection createRemoteIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public final android.telecom.RemoteConnection createRemoteOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public final java.util.Collection<android.telecom.Conference> getAllConferences();
method public final java.util.Collection<android.telecom.Connection> getAllConnections();
method public final android.os.IBinder onBind(android.content.Intent);
method public void onConference(android.telecom.Connection, android.telecom.Connection);
+ method public void onConnectionServiceFocusGained();
+ method public void onConnectionServiceFocusLost();
method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
@@ -41769,8 +41864,6 @@
public deprecated class TestSuiteBuilder {
ctor public TestSuiteBuilder(java.lang.Class);
ctor public TestSuiteBuilder(java.lang.String, java.lang.ClassLoader);
- method public android.test.suitebuilder.TestSuiteBuilder addRequirements(java.util.List<com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>>);
- method public final android.test.suitebuilder.TestSuiteBuilder addRequirements(com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>...);
method public final junit.framework.TestSuite build();
method public android.test.suitebuilder.TestSuiteBuilder excludePackages(java.lang.String...);
method protected java.lang.String getSuiteName();
@@ -46331,6 +46424,7 @@
method public boolean isPressed();
method public boolean isSaveEnabled();
method public boolean isSaveFromParentEnabled();
+ method public boolean isScreenReaderFocusable();
method public boolean isScrollContainer();
method public boolean isScrollbarFadingEnabled();
method public boolean isSelected();
@@ -46550,6 +46644,7 @@
method public void setSaveFromParentEnabled(boolean);
method public void setScaleX(float);
method public void setScaleY(float);
+ method public void setScreenReaderFocusable(boolean);
method public void setScrollBarDefaultDelayBeforeFade(int);
method public void setScrollBarFadeDuration(int);
method public void setScrollBarSize(int);
@@ -47968,6 +48063,7 @@
method public boolean isLongClickable();
method public boolean isMultiLine();
method public boolean isPassword();
+ method public boolean isScreenReaderFocusable();
method public boolean isScrollable();
method public boolean isSelected();
method public boolean isShowingHintText();
@@ -48023,6 +48119,7 @@
method public void setParent(android.view.View, int);
method public void setPassword(boolean);
method public void setRangeInfo(android.view.accessibility.AccessibilityNodeInfo.RangeInfo);
+ method public void setScreenReaderFocusable(boolean);
method public void setScrollable(boolean);
method public void setSelected(boolean);
method public void setShowingHintText(boolean);
@@ -49037,31 +49134,34 @@
package android.view.textclassifier {
public final class TextClassification {
- method public int getActionCount();
method public float getConfidenceScore(java.lang.String);
method public java.lang.String getEntity(int);
method public int getEntityCount();
- method public android.graphics.drawable.Drawable getIcon(int);
method public android.graphics.drawable.Drawable getIcon();
- method public android.content.Intent getIntent(int);
method public android.content.Intent getIntent();
- method public java.lang.CharSequence getLabel(int);
method public java.lang.CharSequence getLabel();
- method public android.view.View.OnClickListener getOnClickListener(int);
method public android.view.View.OnClickListener getOnClickListener();
+ method public int getSecondaryActionsCount();
+ method public android.graphics.drawable.Drawable getSecondaryIcon(int);
+ method public android.content.Intent getSecondaryIntent(int);
+ method public java.lang.CharSequence getSecondaryLabel(int);
+ method public android.view.View.OnClickListener getSecondaryOnClickListener(int);
+ method public java.lang.String getSignature();
method public java.lang.String getText();
}
public static final class TextClassification.Builder {
ctor public TextClassification.Builder();
- method public android.view.textclassifier.TextClassification.Builder addAction(android.content.Intent, java.lang.String, android.graphics.drawable.Drawable, android.view.View.OnClickListener);
+ method public android.view.textclassifier.TextClassification.Builder addSecondaryAction(android.content.Intent, java.lang.String, android.graphics.drawable.Drawable, android.view.View.OnClickListener);
method public android.view.textclassifier.TextClassification build();
- method public android.view.textclassifier.TextClassification.Builder clearActions();
+ method public android.view.textclassifier.TextClassification.Builder clearSecondaryActions();
method public android.view.textclassifier.TextClassification.Builder setEntityType(java.lang.String, float);
method public android.view.textclassifier.TextClassification.Builder setIcon(android.graphics.drawable.Drawable);
method public android.view.textclassifier.TextClassification.Builder setIntent(android.content.Intent);
method public android.view.textclassifier.TextClassification.Builder setLabel(java.lang.String);
method public android.view.textclassifier.TextClassification.Builder setOnClickListener(android.view.View.OnClickListener);
+ method public android.view.textclassifier.TextClassification.Builder setPrimaryAction(android.content.Intent, java.lang.String, android.graphics.drawable.Drawable, android.view.View.OnClickListener);
+ method public android.view.textclassifier.TextClassification.Builder setSignature(java.lang.String);
method public android.view.textclassifier.TextClassification.Builder setText(java.lang.String);
}
@@ -49078,15 +49178,19 @@
public abstract interface TextClassifier {
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.view.textclassifier.TextClassification.Options);
+ method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int);
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence, android.view.textclassifier.TextLinks.Options);
+ method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options);
+ method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
field public static final android.view.textclassifier.TextClassifier NO_OP;
field public static final java.lang.String TYPE_ADDRESS = "address";
field public static final java.lang.String TYPE_EMAIL = "email";
field public static final java.lang.String TYPE_OTHER = "other";
field public static final java.lang.String TYPE_PHONE = "phone";
+ field public static final java.lang.String TYPE_UNKNOWN = "";
field public static final java.lang.String TYPE_URL = "url";
}
@@ -49102,13 +49206,9 @@
}
public static final class TextLinks.Options {
+ ctor public TextLinks.Options();
method public android.os.LocaleList getDefaultLocales();
- }
-
- public static final class TextLinks.Options.Builder {
- ctor public TextLinks.Options.Builder();
- method public android.view.textclassifier.TextLinks.Options build();
- method public android.view.textclassifier.TextLinks.Options.Builder setLocaleList(android.os.LocaleList);
+ method public android.view.textclassifier.TextLinks.Options setDefaultLocales(android.os.LocaleList);
}
public static final class TextLinks.TextLink {
@@ -49126,12 +49226,14 @@
method public int getEntityCount();
method public int getSelectionEndIndex();
method public int getSelectionStartIndex();
+ method public java.lang.String getSignature();
}
public static final class TextSelection.Builder {
ctor public TextSelection.Builder(int, int);
method public android.view.textclassifier.TextSelection build();
method public android.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
+ method public android.view.textclassifier.TextSelection.Builder setSignature(java.lang.String);
}
public static final class TextSelection.Options {
@@ -54852,7 +54954,6 @@
method public java.lang.Object[] getSigners();
method public java.lang.String getSimpleName();
method public java.lang.Class<? super T> getSuperclass();
- method public java.lang.String getTypeName();
method public synchronized java.lang.reflect.TypeVariable<java.lang.Class<T>>[] getTypeParameters();
method public boolean isAnnotation();
method public boolean isAnonymousClass();
@@ -56513,6 +56614,11 @@
ctor public MalformedParameterizedTypeException();
}
+ public class MalformedParametersException extends java.lang.RuntimeException {
+ ctor public MalformedParametersException();
+ ctor public MalformedParametersException(java.lang.String);
+ }
+
public abstract interface Member {
method public abstract java.lang.Class<?> getDeclaringClass();
method public abstract int getModifiers();
@@ -56610,6 +56716,7 @@
}
public abstract interface Type {
+ method public default java.lang.String getTypeName();
}
public abstract interface TypeVariable<D extends java.lang.reflect.GenericDeclaration> implements java.lang.reflect.Type {
diff --git a/api/removed.txt b/api/removed.txt
index 2934846..be4d5be 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -210,10 +210,6 @@
package android.media.tv {
- public final class TvInputManager {
- method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
- }
-
public class TvView extends android.view.ViewGroup {
method public void requestUnblockContent(android.media.tv.TvContentRating);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 990df9b..33fa246 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -126,6 +126,7 @@
field public static final java.lang.String READ_PRINT_SERVICES = "android.permission.READ_PRINT_SERVICES";
field public static final java.lang.String READ_PRINT_SERVICE_RECOMMENDATIONS = "android.permission.READ_PRINT_SERVICE_RECOMMENDATIONS";
field public static final java.lang.String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
+ field public static final java.lang.String READ_RUNTIME_PROFILES = "android.permission.READ_RUNTIME_PROFILES";
field public static final java.lang.String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES";
field public static final java.lang.String READ_WALLPAPER_INTERNAL = "android.permission.READ_WALLPAPER_INTERNAL";
field public static final java.lang.String READ_WIFI_CREDENTIAL = "android.permission.READ_WIFI_CREDENTIAL";
@@ -183,6 +184,7 @@
}
public static final class R.attr {
+ field public static final int isVrOnly = 16844152; // 0x1010578
field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566
field public static final int searchKeyphrase = 16843871; // 0x101045f
@@ -388,6 +390,7 @@
method public void selectBackupTransport(android.content.ComponentName, android.app.backup.SelectBackupTransportCallback);
method public void setAutoRestore(boolean);
method public void setBackupEnabled(boolean);
+ method public void updateTransportAttributes(android.content.ComponentName, java.lang.String, android.content.Intent, java.lang.String, android.content.Intent, java.lang.String);
field public static final int ERROR_AGENT_FAILURE = -1003; // 0xfffffc15
field public static final int ERROR_BACKUP_CANCELLED = -2003; // 0xfffff82d
field public static final int ERROR_BACKUP_NOT_ALLOWED = -2001; // 0xfffff82f
@@ -408,8 +411,9 @@
field public static final java.lang.String EXTRA_LOG_CANCEL_ALL = "android.app.backup.extra.LOG_CANCEL_ALL";
field public static final java.lang.String EXTRA_LOG_EVENT_CATEGORY = "android.app.backup.extra.LOG_EVENT_CATEGORY";
field public static final java.lang.String EXTRA_LOG_EVENT_ID = "android.app.backup.extra.LOG_EVENT_ID";
+ field public static final java.lang.String EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION = "android.app.backup.extra.LOG_EVENT_PACKAGE_FULL_VERSION";
field public static final java.lang.String EXTRA_LOG_EVENT_PACKAGE_NAME = "android.app.backup.extra.LOG_EVENT_PACKAGE_NAME";
- field public static final java.lang.String EXTRA_LOG_EVENT_PACKAGE_VERSION = "android.app.backup.extra.LOG_EVENT_PACKAGE_VERSION";
+ field public static final deprecated java.lang.String EXTRA_LOG_EVENT_PACKAGE_VERSION = "android.app.backup.extra.LOG_EVENT_PACKAGE_VERSION";
field public static final java.lang.String EXTRA_LOG_EXCEPTION_FULL_BACKUP = "android.app.backup.extra.LOG_EXCEPTION_FULL_BACKUP";
field public static final java.lang.String EXTRA_LOG_ILLEGAL_KEY = "android.app.backup.extra.LOG_ILLEGAL_KEY";
field public static final java.lang.String EXTRA_LOG_MANIFEST_PACKAGE_NAME = "android.app.backup.extra.LOG_MANIFEST_PACKAGE_NAME";
@@ -608,8 +612,11 @@
}
public final class UsageStatsManager {
+ method public int getAppStandbyBucket(java.lang.String);
method public void setAppStandbyBucket(java.lang.String, int);
method public void whitelistAppTemporarily(java.lang.String, long, android.os.UserHandle);
+ field public static final int STANDBY_BUCKET_EXEMPTED = 5; // 0x5
+ field public static final int STANDBY_BUCKET_NEVER = 50; // 0x32
}
}
@@ -751,6 +758,20 @@
field public java.lang.String credentialProtectedDataDir;
}
+ public final class InstantAppInfo implements android.os.Parcelable {
+ ctor public InstantAppInfo(android.content.pm.ApplicationInfo, java.lang.String[], java.lang.String[]);
+ ctor public InstantAppInfo(java.lang.String, java.lang.CharSequence, java.lang.String[], java.lang.String[]);
+ method public int describeContents();
+ method public android.content.pm.ApplicationInfo getApplicationInfo();
+ method public java.lang.String[] getGrantedPermissions();
+ method public java.lang.String getPackageName();
+ method public java.lang.String[] getRequestedPermissions();
+ method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
+ method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.content.pm.InstantAppInfo> CREATOR;
+ }
+
public final class InstantAppIntentFilter implements android.os.Parcelable {
ctor public InstantAppIntentFilter(java.lang.String, java.util.List<android.content.IntentFilter>);
method public int describeContents();
@@ -762,13 +783,16 @@
public final class InstantAppResolveInfo implements android.os.Parcelable {
ctor public InstantAppResolveInfo(android.content.pm.InstantAppResolveInfo.InstantAppDigest, java.lang.String, java.util.List<android.content.pm.InstantAppIntentFilter>, int);
+ ctor public InstantAppResolveInfo(android.content.pm.InstantAppResolveInfo.InstantAppDigest, java.lang.String, java.util.List<android.content.pm.InstantAppIntentFilter>, long, android.os.Bundle);
ctor public InstantAppResolveInfo(java.lang.String, java.lang.String, java.util.List<android.content.pm.InstantAppIntentFilter>);
method public int describeContents();
method public byte[] getDigestBytes();
method public int getDigestPrefix();
+ method public android.os.Bundle getExtras();
method public java.util.List<android.content.pm.InstantAppIntentFilter> getIntentFilters();
+ method public long getLongVersionCode();
method public java.lang.String getPackageName();
- method public int getVersionCode();
+ method public deprecated int getVersionCode();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.InstantAppResolveInfo> CREATOR;
}
@@ -825,6 +849,7 @@
public abstract class PackageManager {
method public abstract void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
method public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(java.lang.String);
+ method public android.content.pm.dex.ArtManager getArtManager();
method public abstract java.lang.String getDefaultBrowserPackageNameAsUser(int);
method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
method public abstract android.graphics.drawable.Drawable getInstantAppIcon(java.lang.String);
@@ -932,6 +957,24 @@
}
+package android.content.pm.dex {
+
+ public class ArtManager {
+ method public boolean isRuntimeProfilingEnabled();
+ method public void snapshotRuntimeProfile(java.lang.String, java.lang.String, android.content.pm.dex.ArtManager.SnapshotRuntimeProfileCallback, android.os.Handler);
+ field public static final int SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND = 1; // 0x1
+ field public static final int SNAPSHOT_FAILED_INTERNAL_ERROR = 2; // 0x2
+ field public static final int SNAPSHOT_FAILED_PACKAGE_NOT_FOUND = 0; // 0x0
+ }
+
+ public static abstract class ArtManager.SnapshotRuntimeProfileCallback {
+ ctor public ArtManager.SnapshotRuntimeProfileCallback();
+ method public abstract void onError(int);
+ method public abstract void onSuccess(android.os.ParcelFileDescriptor);
+ }
+
+}
+
package android.content.pm.permission {
public final class RuntimePermissionPresentationInfo implements android.os.Parcelable {
@@ -4088,6 +4131,7 @@
method public java.lang.String getCdmaMdn(int);
method public java.lang.String getCdmaMin();
method public java.lang.String getCdmaMin(int);
+ method public java.lang.String getCdmaPrlVersion();
method public int getCurrentPhoneType();
method public int getCurrentPhoneType(int);
method public deprecated boolean getDataEnabled();
@@ -4133,6 +4177,25 @@
package android.telephony.data {
+ public final class DataCallResponse implements android.os.Parcelable {
+ ctor public DataCallResponse(int, int, int, int, java.lang.String, java.lang.String, java.util.List<android.telephony.data.InterfaceAddress>, java.util.List<java.net.InetAddress>, java.util.List<java.net.InetAddress>, java.util.List<java.lang.String>, int);
+ ctor public DataCallResponse(android.os.Parcel);
+ method public int describeContents();
+ method public int getActive();
+ method public java.util.List<android.telephony.data.InterfaceAddress> getAddresses();
+ method public int getCallId();
+ method public java.util.List<java.net.InetAddress> getDnses();
+ method public java.util.List<java.net.InetAddress> getGateways();
+ method public java.lang.String getIfname();
+ method public int getMtu();
+ method public java.util.List<java.lang.String> getPcscfs();
+ method public int getStatus();
+ method public int getSuggestedRetryTime();
+ method public java.lang.String getType();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR;
+ }
+
public final class DataProfile implements android.os.Parcelable {
ctor public DataProfile(int, java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, int, int, int, int, boolean, int, java.lang.String, int, int, java.lang.String, java.lang.String, boolean);
ctor public DataProfile(android.os.Parcel);
@@ -4162,6 +4225,17 @@
field public static final int TYPE_COMMON = 0; // 0x0
}
+ public final class InterfaceAddress implements android.os.Parcelable {
+ ctor public InterfaceAddress(java.net.InetAddress, int);
+ ctor public InterfaceAddress(java.lang.String, int) throws java.net.UnknownHostException;
+ ctor public InterfaceAddress(android.os.Parcel);
+ method public int describeContents();
+ method public java.net.InetAddress getAddress();
+ method public int getNetworkPrefixLength();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.data.InterfaceAddress> CREATOR;
+ }
+
}
package android.telephony.ims {
@@ -4314,6 +4388,7 @@
public final class StatsManager {
method public boolean addConfiguration(java.lang.String, byte[], java.lang.String, java.lang.String);
method public byte[] getData(java.lang.String);
+ method public byte[] getMetadata();
method public boolean removeConfiguration(java.lang.String);
}
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 396bcd6..f98d011 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -103,6 +103,10 @@
package android.media.tv {
+ public final class TvInputManager {
+ method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+ }
+
public static final class TvInputManager.Hardware {
method public boolean dispatchKeyEventToHdmi(android.view.KeyEvent);
}
@@ -111,6 +115,13 @@
package android.net.wifi {
+ public deprecated class BatchedScanResult implements android.os.Parcelable {
+ ctor public BatchedScanResult();
+ ctor public BatchedScanResult(android.net.wifi.BatchedScanResult);
+ field public final java.util.List<android.net.wifi.ScanResult> scanResults;
+ field public boolean truncated;
+ }
+
public class ScanResult implements android.os.Parcelable {
field public boolean untrusted;
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 8647ed3..3c3521f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -18,7 +18,7 @@
method public void removeStacksWithActivityTypes(int[]) throws java.lang.SecurityException;
method public void resizeStack(int, android.graphics.Rect) throws java.lang.SecurityException;
method public void setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException;
- method public void setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect) throws java.lang.SecurityException;
+ method public void setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect, boolean) throws java.lang.SecurityException;
method public static boolean supportsMultiWindow(android.content.Context);
method public static boolean supportsSplitScreenMultiWindow(android.content.Context);
field public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1; // 0x1
@@ -425,7 +425,7 @@
public static final class Settings.Secure extends android.provider.Settings.NameValueTable {
field public static final java.lang.String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED = "accessibility_display_magnification_enabled";
- field public static final java.lang.String AUTOFILL_FEATURE_FIELD_DETECTION = "autofill_field_detection";
+ field public static final java.lang.String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification";
field public static final java.lang.String AUTOFILL_SERVICE = "autofill_service";
field public static final java.lang.String DISABLED_PRINT_SERVICES = "disabled_print_services";
field public static final deprecated java.lang.String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES = "enabled_notification_policy_access_packages";
@@ -457,19 +457,35 @@
method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
}
- public final class FieldsDetection implements android.os.Parcelable {
- ctor public FieldsDetection(android.view.autofill.AutofillId, java.lang.String, java.lang.String);
+ public final class EditDistanceScorer extends android.service.autofill.InternalScorer implements android.os.Parcelable android.service.autofill.Scorer {
method public int describeContents();
+ method public static android.service.autofill.EditDistanceScorer getInstance();
+ method public float getScore(android.view.autofill.AutofillValue, java.lang.String);
method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.service.autofill.FieldsDetection> CREATOR;
+ field public static final android.os.Parcelable.Creator<android.service.autofill.EditDistanceScorer> CREATOR;
+ }
+
+ public final class FieldClassification implements android.os.Parcelable {
+ method public int describeContents();
+ method public java.util.List<android.service.autofill.FieldClassification.Match> getMatches();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.FieldClassification> CREATOR;
+ }
+
+ public static final class FieldClassification.Match implements android.os.Parcelable {
+ method public int describeContents();
+ method public java.lang.String getRemoteId();
+ method public float getScore();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.FieldClassification.Match> CREATOR;
}
public static final class FillEventHistory.Event {
- method public java.util.Map<java.lang.String, java.lang.Integer> getDetectedFields();
+ method public java.util.Map<android.view.autofill.AutofillId, android.service.autofill.FieldClassification> getFieldsClassification();
}
public static final class FillResponse.Builder {
- method public android.service.autofill.FillResponse.Builder setFieldsDetection(android.service.autofill.FieldsDetection);
+ method public android.service.autofill.FillResponse.Builder setFieldClassificationIds(android.view.autofill.AutofillId...);
}
public final class ImageTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
@@ -480,6 +496,11 @@
ctor public InternalSanitizer();
}
+ public abstract class InternalScorer implements android.os.Parcelable android.service.autofill.Scorer {
+ ctor public InternalScorer();
+ method public abstract float getScore(android.view.autofill.AutofillValue, java.lang.String);
+ }
+
public abstract class InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
ctor public InternalTransformation();
}
@@ -497,10 +518,29 @@
method public boolean isValid(android.service.autofill.ValueFinder);
}
+ public abstract interface Scorer {
+ }
+
public final class TextValueSanitizer extends android.service.autofill.InternalSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
method public android.view.autofill.AutofillValue sanitize(android.view.autofill.AutofillValue);
}
+ public final class UserData implements android.os.Parcelable {
+ method public int describeContents();
+ method public static int getMaxFieldClassificationIdsSize();
+ method public static int getMaxUserDataSize();
+ method public static int getMaxValueLength();
+ method public static int getMinValueLength();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.UserData> CREATOR;
+ }
+
+ public static final class UserData.Builder {
+ ctor public UserData.Builder(android.service.autofill.Scorer, java.lang.String, java.lang.String);
+ method public android.service.autofill.UserData.Builder add(java.lang.String, java.lang.String);
+ method public android.service.autofill.UserData build();
+ }
+
public abstract interface ValueFinder {
method public abstract java.lang.String findByAutofillId(android.view.autofill.AutofillId);
}
@@ -591,32 +631,6 @@
}
-package android.telecom {
-
- public abstract class Connection extends android.telecom.Conferenceable {
- method public void handleRttUpgradeResponse(android.telecom.Connection.RttTextStream);
- method public void onStartRtt(android.telecom.Connection.RttTextStream);
- method public void onStopRtt();
- method public final void sendRemoteRttRequest();
- method public final void sendRttInitiationFailure(int);
- method public final void sendRttInitiationSuccess();
- method public final void sendRttSessionRemotelyTerminated();
- field public static final int PROPERTY_IS_RTT = 256; // 0x100
- }
-
- public static final class Connection.RttTextStream {
- method public java.lang.String read() throws java.io.IOException;
- method public java.lang.String readImmediately() throws java.io.IOException;
- method public void write(java.lang.String) throws java.io.IOException;
- }
-
- public final class ConnectionRequest implements android.os.Parcelable {
- method public android.telecom.Connection.RttTextStream getRttTextStream();
- method public boolean isRequestingRtt();
- }
-
-}
-
package android.telephony {
public class MbmsDownloadSession implements java.lang.AutoCloseable {
@@ -974,6 +988,12 @@
ctor public AutofillId(int);
}
+ public final class AutofillManager {
+ method public android.service.autofill.UserData getUserData();
+ method public boolean isFieldClassificationEnabled();
+ method public void setUserData(android.service.autofill.UserData);
+ }
+
}
package android.widget {
diff --git a/cmds/incidentd/src/Privacy.cpp b/cmds/incidentd/src/Privacy.cpp
index 140b12c..5db2239 100644
--- a/cmds/incidentd/src/Privacy.cpp
+++ b/cmds/incidentd/src/Privacy.cpp
@@ -16,37 +16,18 @@
#include "Privacy.h"
+#include <android/os/IncidentReportArgs.h>
#include <stdlib.h>
-// DESTINATION enum value
-const uint8_t DEST_LOCAL = 0;
-const uint8_t DEST_EXPLICIT = 1;
-const uint8_t DEST_AUTOMATIC = 2;
+uint64_t encode_field_id(const Privacy* p) { return (uint64_t)p->type << 32 | p->field_id; }
-// type of the field, identitical to protobuf definition
-const uint8_t TYPE_STRING = 9;
-const uint8_t TYPE_MESSAGE = 11;
-
-bool
-Privacy::IsMessageType() const { return type == TYPE_MESSAGE; }
-
-uint64_t
-Privacy::EncodedFieldId() const { return (uint64_t)type << 32 | field_id; }
-
-bool
-Privacy::IsStringType() const { return type == TYPE_STRING; }
-
-bool
-Privacy::HasChildren() const { return children != NULL && children[0] != NULL; }
-
-const Privacy*
-Privacy::lookup(uint32_t fieldId) const
+const Privacy* lookup(const Privacy* p, uint32_t fieldId)
{
- if (children == NULL) return NULL;
- for (int i=0; children[i] != NULL; i++) {
- if (children[i]->field_id == fieldId) return children[i];
- // This assumes the list's field id is in ascending order and must be true.
- if (children[i]->field_id > fieldId) return NULL;
+ if (p->children == NULL) return NULL;
+ for (int i=0; p->children[i] != NULL; i++) { // NULL-terminated.
+ if (p->children[i]->field_id == fieldId) return p->children[i];
+ // Incident section gen tool guarantees field ids in ascending order.
+ if (p->children[i]->field_id > fieldId) return NULL;
}
return NULL;
}
@@ -54,11 +35,14 @@
static bool allowDest(const uint8_t dest, const uint8_t policy)
{
switch (policy) {
- case DEST_LOCAL:
- return dest == DEST_LOCAL;
- case DEST_EXPLICIT:
- return dest == DEST_LOCAL || dest == DEST_EXPLICIT;
- case DEST_AUTOMATIC:
+ case android::os::DEST_LOCAL:
+ return dest == android::os::DEST_LOCAL;
+ case android::os::DEST_EXPLICIT:
+ case DEST_UNSET:
+ return dest == android::os::DEST_LOCAL ||
+ dest == android::os::DEST_EXPLICIT ||
+ dest == DEST_UNSET;
+ case android::os::DEST_AUTOMATIC:
return true;
default:
return false;
@@ -72,18 +56,19 @@
}
bool
-PrivacySpec::CheckPremission(const Privacy* privacy) const
+PrivacySpec::CheckPremission(const Privacy* privacy, const uint8_t defaultDest) const
{
- uint8_t policy = privacy == NULL ? DEST_DEFAULT_VALUE : privacy->dest;
+ uint8_t policy = privacy != NULL ? privacy->dest : defaultDest;
return allowDest(dest, policy);
}
bool
-PrivacySpec::RequireAll() const { return dest == DEST_LOCAL; }
+PrivacySpec::RequireAll() const { return dest == android::os::DEST_LOCAL; }
-PrivacySpec new_spec_from_args(int dest) {
+PrivacySpec new_spec_from_args(int dest)
+{
if (dest < 0) return PrivacySpec();
return PrivacySpec(dest);
}
-PrivacySpec get_default_dropbox_spec() { return PrivacySpec(DEST_AUTOMATIC); }
\ No newline at end of file
+PrivacySpec get_default_dropbox_spec() { return PrivacySpec(android::os::DEST_AUTOMATIC); }
\ No newline at end of file
diff --git a/cmds/incidentd/src/Privacy.h b/cmds/incidentd/src/Privacy.h
index f514f19..9e15ff4 100644
--- a/cmds/incidentd/src/Privacy.h
+++ b/cmds/incidentd/src/Privacy.h
@@ -19,35 +19,46 @@
#include <stdint.h>
-// This is the default value of DEST enum
-const uint8_t DEST_DEFAULT_VALUE = 1;
+// This is the default value of DEST enum, sync with privacy.proto
+const uint8_t DEST_UNSET = 255; // DEST_UNSET is not exposed to libincident
+const uint8_t DEST_DEFAULT_VALUE = DEST_UNSET;
/*
- * In order not to depend on libprotobuf-cpp-full nor libplatformprotos in incidentd,
- * privacy options's data structure are explicitly redefined in this file.
+ * In order to NOT auto-generate large chuck of code by proto compiler in incidentd,
+ * privacy options's data structure are explicitly redefined here and
+ * the values are populated by incident_section_gen tool.
+ *
+ * Each proto field will have a Privacy when it is different from its parent, otherwise
+ * it uses its parent's tag. A message type will have an array of Privacy.
*/
struct Privacy {
+ // The field number
uint32_t field_id;
+
+ // The field type, see external/protobuf/src/google/protobuf/descriptor.h
uint8_t type;
- // ignore parent's privacy flags if children are set, NULL-terminated
+
+ // If children is null, it is a primitive field,
+ // otherwise it is a message field which could have overridden privacy tags here.
+ // This array is NULL-terminated.
Privacy** children;
- // the following fields are identitical to
- // frameworks/base/libs/incident/proto/android/privacy.proto
+ // DESTINATION Enum in frameworks/base/libs/incident/proto/android/privacy.proto.
uint8_t dest;
- const char** patterns; // only set when type is string
-
- bool IsMessageType() const;
- bool IsStringType() const;
- bool HasChildren() const;
- uint64_t EncodedFieldId() const;
-
- const Privacy* lookup(uint32_t fieldId) const;
+ // A list of regexp rules for stripping string fields in proto.
+ const char** patterns;
};
+// Encode field id used by ProtoOutputStream.
+uint64_t encode_field_id(const Privacy* p);
+
+// Look up the child with given fieldId, if not found, return NULL.
+const Privacy* lookup(const Privacy* p, uint32_t fieldId);
+
/**
* PrivacySpec defines the request has what level of privacy authorization.
* For example, a device without user consent should only be able to upload AUTOMATIC fields.
+ * DEST_UNSET are treated as DEST_EXPLICIT.
*/
class PrivacySpec {
public:
@@ -58,7 +69,10 @@
bool operator<(const PrivacySpec& other) const;
- bool CheckPremission(const Privacy* privacy) const;
+ // check permission of a policy, if returns true, don't strip the data.
+ bool CheckPremission(const Privacy* privacy, const uint8_t defaultDest = DEST_DEFAULT_VALUE) const;
+
+ // if returns true, no data need to be stripped.
bool RequireAll() const;
};
diff --git a/cmds/incidentd/src/PrivacyBuffer.cpp b/cmds/incidentd/src/PrivacyBuffer.cpp
index 77ae1a7..03faa92 100644
--- a/cmds/incidentd/src/PrivacyBuffer.cpp
+++ b/cmds/incidentd/src/PrivacyBuffer.cpp
@@ -14,15 +14,18 @@
* limitations under the License.
*/
-
+#define LOG_TAG "incidentd"
#include "PrivacyBuffer.h"
#include "io_util.h"
#include <android/util/protobuf.h>
+#include <cutils/log.h>
using namespace android::util;
+const bool DEBUG = false;
+
/**
* Write the field to buf based on the wire type, iterator will point to next field.
* If skip is set to true, no data will be written to buf. Return number of bytes written.
@@ -30,6 +33,9 @@
void
PrivacyBuffer::writeFieldOrSkip(uint32_t fieldTag, bool skip)
{
+ if (DEBUG) ALOGD("%s field %d (wiretype = %d)", skip ? "skip" : "write",
+ read_field_id(fieldTag), read_wire_type(fieldTag));
+
uint8_t wireType = read_wire_type(fieldTag);
size_t bytesToWrite = 0;
uint32_t varint = 0;
@@ -55,6 +61,7 @@
bytesToWrite = 4;
break;
}
+ if (DEBUG) ALOGD("%s %d bytes of data", skip ? "skip" : "write", (int)bytesToWrite);
if (skip) {
mData.rp()->move(bytesToWrite);
} else {
@@ -76,10 +83,13 @@
{
if (!mData.hasNext() || parentPolicy == NULL) return BAD_VALUE;
uint32_t fieldTag = mData.readRawVarint();
- const Privacy* policy = parentPolicy->lookup(read_field_id(fieldTag));
+ const Privacy* policy = lookup(parentPolicy, read_field_id(fieldTag));
- if (policy == NULL || !policy->IsMessageType() || !policy->HasChildren()) {
- bool skip = !spec.CheckPremission(policy);
+ if (policy == NULL || policy->children == NULL) {
+ if (DEBUG) ALOGD("Not a message field %d: dest(%d)", read_field_id(fieldTag),
+ policy != NULL ? policy->dest : parentPolicy->dest);
+
+ bool skip = !spec.CheckPremission(policy, parentPolicy->dest);
// iterator will point to head of next field
writeFieldOrSkip(fieldTag, skip);
return NO_ERROR;
@@ -87,7 +97,7 @@
// current field is message type and its sub-fields have extra privacy policies
uint32_t msgSize = mData.readRawVarint();
EncodedBuffer::Pointer start = mData.rp()->copy();
- long long token = mProto.start(policy->EncodedFieldId());
+ long long token = mProto.start(encode_field_id(policy));
while (mData.rp()->pos() - start.pos() != msgSize) {
status_t err = stripField(policy, spec);
if (err != NO_ERROR) return err;
@@ -112,8 +122,9 @@
status_t
PrivacyBuffer::strip(const PrivacySpec& spec)
{
+ if (DEBUG) ALOGD("Strip with spec %d", spec.dest);
// optimization when no strip happens
- if (mPolicy == NULL || !mPolicy->HasChildren() || spec.RequireAll()) {
+ if (mPolicy == NULL || mPolicy->children == NULL || spec.RequireAll()) {
if (spec.CheckPremission(mPolicy)) mSize = mData.size();
return NO_ERROR;
}
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index c08b9ea..1bf795b 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -210,9 +210,9 @@
{
for (ReportRequestSet::iterator it=requests->begin(); it!=requests->end(); it++) {
const sp<ReportRequest> request = *it;
- const vector<vector<int8_t>>& headers = request->args.headers();
+ const vector<vector<uint8_t>>& headers = request->args.headers();
- for (vector<vector<int8_t>>::const_iterator buf=headers.begin(); buf!=headers.end(); buf++) {
+ for (vector<vector<uint8_t>>::const_iterator buf=headers.begin(); buf!=headers.end(); buf++) {
if (buf->empty()) continue;
// So the idea is only requests with negative fd are written to dropbox file.
diff --git a/cmds/incidentd/src/io_util.cpp b/cmds/incidentd/src/io_util.cpp
index f043d36..af4a35c 100644
--- a/cmds/incidentd/src/io_util.cpp
+++ b/cmds/incidentd/src/io_util.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "incidentd"
+
#include "io_util.h"
#include <unistd.h>
diff --git a/cmds/incidentd/tests/PrivacyBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
index ca94623..32b9e42 100644
--- a/cmds/incidentd/tests/PrivacyBuffer_test.cpp
+++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
@@ -12,27 +12,27 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#define LOG_TAG "incidentd"
+
#include "FdBuffer.h"
#include "PrivacyBuffer.h"
#include <android-base/file.h>
#include <android-base/test_utils.h>
+#include <android/os/IncidentReportArgs.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <string.h>
using namespace android;
using namespace android::base;
+using namespace android::os;
using namespace std;
using ::testing::StrEq;
using ::testing::Test;
using ::testing::internal::CaptureStdout;
using ::testing::internal::GetCapturedStdout;
-const uint8_t LOCAL = 0;
-const uint8_t EXPLICIT = 1;
-const uint8_t AUTOMATIC = 2;
-
const uint8_t OTHER_TYPE = 1;
const uint8_t STRING_TYPE = 9;
const uint8_t MESSAGE_TYPE = 11;
@@ -109,21 +109,11 @@
p->field_id = field_id;
p->type = MESSAGE_TYPE;
p->children = children;
- p->dest = EXPLICIT;
+ p->dest = DEST_DEFAULT_VALUE;
p->patterns = NULL;
return p;
}
- Privacy* create_string_privacy(uint32_t field_id, uint8_t dest, const char** patterns) {
- Privacy* p = new_uninit_privacy();
- p->field_id = field_id;
- p->type = STRING_TYPE;
- p->children = NULL;
- p->dest = dest;
- p->patterns = patterns;
- return p;
- }
-
FdBuffer buffer;
private:
TemporaryFile tf;
@@ -138,103 +128,103 @@
}
};
-TEST_F(PrivacyBufferTest, NullFieldPolicy) {
+TEST_F(PrivacyBufferTest, NullPolicy) {
writeToFdBuffer(STRING_FIELD_0);
- assertStrip(EXPLICIT, STRING_FIELD_0, create_string_privacy(300, AUTOMATIC, NULL));
+ assertStrip(DEST_EXPLICIT, STRING_FIELD_0, NULL);
}
-TEST_F(PrivacyBufferTest, StripSpecNotAllowed) {
+TEST_F(PrivacyBufferTest, StripUnsetField) {
writeToFdBuffer(STRING_FIELD_0);
- assertStripByFields(AUTOMATIC, "", 1, create_privacy(0, STRING_TYPE, EXPLICIT));
+ assertStripByFields(DEST_AUTOMATIC, "", 1, create_privacy(0, STRING_TYPE, DEST_UNSET));
}
TEST_F(PrivacyBufferTest, StripVarintField) {
writeToFdBuffer(VARINT_FIELD_1);
- assertStripByFields(EXPLICIT, "", 1, create_privacy(1, OTHER_TYPE, LOCAL));
+ assertStripByFields(DEST_EXPLICIT, "", 1, create_privacy(1, OTHER_TYPE, DEST_LOCAL));
}
TEST_F(PrivacyBufferTest, StripLengthDelimitedField_String) {
writeToFdBuffer(STRING_FIELD_2);
- assertStripByFields(EXPLICIT, "", 1, create_privacy(2, STRING_TYPE, LOCAL));
+ assertStripByFields(DEST_EXPLICIT, "", 1, create_privacy(2, STRING_TYPE, DEST_LOCAL));
}
TEST_F(PrivacyBufferTest, StripFixed64Field) {
writeToFdBuffer(FIX64_FIELD_3);
- assertStripByFields(EXPLICIT, "", 1, create_privacy(3, OTHER_TYPE, LOCAL));
+ assertStripByFields(DEST_EXPLICIT, "", 1, create_privacy(3, OTHER_TYPE, DEST_LOCAL));
}
TEST_F(PrivacyBufferTest, StripFixed32Field) {
writeToFdBuffer(FIX32_FIELD_4);
- assertStripByFields(EXPLICIT, "", 1, create_privacy(4, OTHER_TYPE, LOCAL));
+ assertStripByFields(DEST_EXPLICIT, "", 1, create_privacy(4, OTHER_TYPE, DEST_LOCAL));
}
TEST_F(PrivacyBufferTest, StripLengthDelimitedField_Message) {
writeToFdBuffer(MESSAGE_FIELD_5);
- assertStripByFields(EXPLICIT, "", 1, create_privacy(5, MESSAGE_TYPE, LOCAL));
+ assertStripByFields(DEST_EXPLICIT, "", 1, create_privacy(5, MESSAGE_TYPE, DEST_LOCAL));
}
TEST_F(PrivacyBufferTest, NoStripVarintField) {
writeToFdBuffer(VARINT_FIELD_1);
- assertStripByFields(EXPLICIT, VARINT_FIELD_1, 1, create_privacy(1, OTHER_TYPE, AUTOMATIC));
+ assertStripByFields(DEST_EXPLICIT, VARINT_FIELD_1, 1, create_privacy(1, OTHER_TYPE, DEST_AUTOMATIC));
}
TEST_F(PrivacyBufferTest, NoStripLengthDelimitedField_String) {
writeToFdBuffer(STRING_FIELD_2);
- assertStripByFields(EXPLICIT, STRING_FIELD_2, 1, create_privacy(2, STRING_TYPE, AUTOMATIC));
+ assertStripByFields(DEST_EXPLICIT, STRING_FIELD_2, 1, create_privacy(2, STRING_TYPE, DEST_AUTOMATIC));
}
TEST_F(PrivacyBufferTest, NoStripFixed64Field) {
writeToFdBuffer(FIX64_FIELD_3);
- assertStripByFields(EXPLICIT, FIX64_FIELD_3, 1, create_privacy(3, OTHER_TYPE, AUTOMATIC));
+ assertStripByFields(DEST_EXPLICIT, FIX64_FIELD_3, 1, create_privacy(3, OTHER_TYPE, DEST_AUTOMATIC));
}
TEST_F(PrivacyBufferTest, NoStripFixed32Field) {
writeToFdBuffer(FIX32_FIELD_4);
- assertStripByFields(EXPLICIT, FIX32_FIELD_4, 1, create_privacy(4, OTHER_TYPE, AUTOMATIC));
+ assertStripByFields(DEST_EXPLICIT, FIX32_FIELD_4, 1, create_privacy(4, OTHER_TYPE, DEST_AUTOMATIC));
}
TEST_F(PrivacyBufferTest, NoStripLengthDelimitedField_Message) {
writeToFdBuffer(MESSAGE_FIELD_5);
- assertStripByFields(EXPLICIT, MESSAGE_FIELD_5, 1, create_privacy(5, MESSAGE_TYPE, AUTOMATIC));
+ assertStripByFields(DEST_EXPLICIT, MESSAGE_FIELD_5, 1, create_privacy(5, MESSAGE_TYPE, DEST_AUTOMATIC));
}
TEST_F(PrivacyBufferTest, StripVarintAndString) {
writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2
+ FIX64_FIELD_3 + FIX32_FIELD_4);
string expected = STRING_FIELD_0 + FIX64_FIELD_3 + FIX32_FIELD_4;
- assertStripByFields(EXPLICIT, expected, 2,
- create_privacy(1, OTHER_TYPE, LOCAL), create_privacy(2, STRING_TYPE, LOCAL));
+ assertStripByFields(DEST_EXPLICIT, expected, 2,
+ create_privacy(1, OTHER_TYPE, DEST_LOCAL), create_privacy(2, STRING_TYPE, DEST_LOCAL));
}
TEST_F(PrivacyBufferTest, StripVarintAndFixed64) {
writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2
+ FIX64_FIELD_3 + FIX32_FIELD_4);
string expected = STRING_FIELD_0 + STRING_FIELD_2 + FIX32_FIELD_4;
- assertStripByFields(EXPLICIT, expected, 2,
- create_privacy(1, OTHER_TYPE, LOCAL), create_privacy(3, OTHER_TYPE, LOCAL));
+ assertStripByFields(DEST_EXPLICIT, expected, 2,
+ create_privacy(1, OTHER_TYPE, DEST_LOCAL), create_privacy(3, OTHER_TYPE, DEST_LOCAL));
}
TEST_F(PrivacyBufferTest, StripVarintInNestedMessage) {
writeToFdBuffer(STRING_FIELD_0 + MESSAGE_FIELD_5);
- Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL };
+ Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
string expected = STRING_FIELD_0 + "\x2a\xd" + STRING_FIELD_2;
- assertStripByFields(EXPLICIT, expected, 1, create_message_privacy(5, list));
+ assertStripByFields(DEST_EXPLICIT, expected, 1, create_message_privacy(5, list));
}
TEST_F(PrivacyBufferTest, StripFix64AndVarintInNestedMessage) {
writeToFdBuffer(STRING_FIELD_0 + FIX64_FIELD_3 + MESSAGE_FIELD_5);
- Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL };
+ Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
string expected = STRING_FIELD_0 + "\x2a\xd" + STRING_FIELD_2;
- assertStripByFields(EXPLICIT, expected, 2, create_privacy(3, OTHER_TYPE, LOCAL), create_message_privacy(5, list));
+ assertStripByFields(DEST_EXPLICIT, expected, 2, create_privacy(3, OTHER_TYPE, DEST_LOCAL), create_message_privacy(5, list));
}
TEST_F(PrivacyBufferTest, ClearAndStrip) {
string data = STRING_FIELD_0 + VARINT_FIELD_1;
writeToFdBuffer(data);
- Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL };
+ Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
EncodedBuffer::iterator bufData = buffer.data();
PrivacyBuffer privacyBuf(create_message_privacy(300, list), bufData);
- PrivacySpec spec1(EXPLICIT), spec2(LOCAL);
+ PrivacySpec spec1(DEST_EXPLICIT), spec2(DEST_LOCAL);
ASSERT_EQ(privacyBuf.strip(spec1), NO_ERROR);
assertBuffer(privacyBuf, STRING_FIELD_0);
@@ -244,7 +234,7 @@
TEST_F(PrivacyBufferTest, BadDataInFdBuffer) {
writeToFdBuffer("iambaddata");
- Privacy* list[] = { create_privacy(4, OTHER_TYPE, AUTOMATIC), NULL };
+ Privacy* list[] = { create_privacy(4, OTHER_TYPE, DEST_AUTOMATIC), NULL };
EncodedBuffer::iterator bufData = buffer.data();
PrivacyBuffer privacyBuf(create_message_privacy(300, list), bufData);
PrivacySpec spec;
@@ -253,7 +243,7 @@
TEST_F(PrivacyBufferTest, BadDataInNestedMessage) {
writeToFdBuffer(STRING_FIELD_0 + MESSAGE_FIELD_5 + "aoeoe");
- Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL };
+ Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
Privacy* field5[] = { create_message_privacy(5, list), NULL };
EncodedBuffer::iterator bufData = buffer.data();
PrivacyBuffer privacyBuf(create_message_privacy(300, field5), bufData);
@@ -265,8 +255,17 @@
string input = "\x2a\"" + VARINT_FIELD_1 + STRING_FIELD_2 + MESSAGE_FIELD_5;
writeToFdBuffer(input);
Privacy* field5 = create_message_privacy(5, NULL);
- Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), field5, NULL };
+ Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), field5, NULL };
field5->children = list;
string expected = "\x2a\x1c" + STRING_FIELD_2 + "\x2a\xd" + STRING_FIELD_2;
- assertStrip(EXPLICIT, expected, field5);
+ assertStrip(DEST_EXPLICIT, expected, field5);
}
+
+TEST_F(PrivacyBufferTest, AutoMessage) {
+ writeToFdBuffer(STRING_FIELD_2 + MESSAGE_FIELD_5);
+ Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
+ Privacy* autoMsg = create_privacy(5, MESSAGE_TYPE, DEST_AUTOMATIC);
+ autoMsg->children = list;
+ string expected = "\x2a\xd" + STRING_FIELD_2;
+ assertStripByFields(DEST_AUTOMATIC, expected, 1, autoMsg);
+}
\ No newline at end of file
diff --git a/cmds/incidentd/tests/Reporter_test.cpp b/cmds/incidentd/tests/Reporter_test.cpp
index 8d99fc7..531c9f2 100644
--- a/cmds/incidentd/tests/Reporter_test.cpp
+++ b/cmds/incidentd/tests/Reporter_test.cpp
@@ -141,7 +141,7 @@
IncidentReportArgs args1, args2;
args1.addSection(1);
args2.addSection(2);
- std::vector<int8_t> header {'a', 'b', 'c', 'd', 'e'};
+ std::vector<uint8_t> header {'a', 'b', 'c', 'd', 'e'};
args2.addHeader(header);
sp<ReportRequest> r1 = new ReportRequest(args1, l, tf.fd);
sp<ReportRequest> r2 = new ReportRequest(args2, l, tf.fd);
diff --git a/cmds/incidentd/tests/Section_test.cpp b/cmds/incidentd/tests/Section_test.cpp
index 649e908..0c7876c 100644
--- a/cmds/incidentd/tests/Section_test.cpp
+++ b/cmds/incidentd/tests/Section_test.cpp
@@ -66,12 +66,12 @@
args1.addSection(2);
args2.setAll(true);
- vector<int8_t> head1;
+ vector<uint8_t> head1;
head1.push_back('a');
head1.push_back('x');
head1.push_back('e');
- vector<int8_t> head2;
+ vector<uint8_t> head2;
head2.push_back('p');
head2.push_back('u');
head2.push_back('p');
diff --git a/cmds/incidentd/tests/section_list.cpp b/cmds/incidentd/tests/section_list.cpp
index 4acc429..1d6213f 100644
--- a/cmds/incidentd/tests/section_list.cpp
+++ b/cmds/incidentd/tests/section_list.cpp
@@ -5,20 +5,16 @@
NULL
};
-const uint8_t LOCAL = 0;
-const uint8_t EXPLICIT = 1;
-const uint8_t AUTOMATIC = 2;
-
-Privacy sub_field_1 { 1, 1, NULL, LOCAL, NULL };
-Privacy sub_field_2 { 2, 9, NULL, AUTOMATIC, NULL };
+Privacy sub_field_1 { 1, 1, NULL, DEST_LOCAL, NULL };
+Privacy sub_field_2 { 2, 9, NULL, DEST_AUTOMATIC, NULL };
Privacy* list[] = {
&sub_field_1,
&sub_field_2,
NULL };
-Privacy field_0 { 0, 11, list, EXPLICIT, NULL };
-Privacy field_1 { 1, 9, NULL, AUTOMATIC, NULL };
+Privacy field_0 { 0, 11, list, DEST_EXPLICIT, NULL };
+Privacy field_1 { 1, 9, NULL, DEST_AUTOMATIC, NULL };
Privacy* final_list[] = {
&field_0,
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 6ded246..3172281 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -159,7 +159,7 @@
void const* mapbase = MAP_FAILED;
ssize_t mapsize = -1;
- void const* base = NULL;
+ void* base = NULL;
uint32_t w, s, h, f;
android_dataspace d;
size_t size = 0;
@@ -179,7 +179,6 @@
ProcessState::self()->setThreadPoolMaxThreadCount(0);
ProcessState::self()->startThreadPool();
- ScreenshotClient screenshot;
sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId);
if (display == NULL) {
fprintf(stderr, "Unable to get handle for display %d\n", displayId);
@@ -199,51 +198,57 @@
uint8_t displayOrientation = configs[activeConfig].orientation;
uint32_t captureOrientation = ORIENTATION_MAP[displayOrientation];
- status_t result = screenshot.update(display, Rect(),
- 0 /* reqWidth */, 0 /* reqHeight */,
- INT32_MIN, INT32_MAX, /* all layers */
- false, captureOrientation);
- if (result == NO_ERROR) {
- base = screenshot.getPixels();
- w = screenshot.getWidth();
- h = screenshot.getHeight();
- s = screenshot.getStride();
- f = screenshot.getFormat();
- d = screenshot.getDataSpace();
- size = screenshot.getSize();
+ sp<GraphicBuffer> outBuffer;
+ status_t result = ScreenshotClient::capture(display, Rect(), 0 /* reqWidth */,
+ 0 /* reqHeight */, INT32_MIN, INT32_MAX, /* all layers */ false, captureOrientation,
+ &outBuffer);
+ if (result != NO_ERROR) {
+ close(fd);
+ _exit(1);
}
- if (base != NULL) {
- if (png) {
- const SkImageInfo info =
- SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType,
- dataSpaceToColorSpace(d));
- SkPixmap pixmap(info, base, s * bytesPerPixel(f));
- struct FDWStream final : public SkWStream {
- size_t fBytesWritten = 0;
- int fFd;
- FDWStream(int f) : fFd(f) {}
- size_t bytesWritten() const override { return fBytesWritten; }
- bool write(const void* buffer, size_t size) override {
- fBytesWritten += size;
- return size == 0 || ::write(fFd, buffer, size) > 0;
- }
- } fdStream(fd);
- (void)SkEncodeImage(&fdStream, pixmap, SkEncodedImageFormat::kPNG, 100);
- if (fn != NULL) {
- notifyMediaScanner(fn);
- }
- } else {
- uint32_t c = dataSpaceToInt(d);
- write(fd, &w, 4);
- write(fd, &h, 4);
- write(fd, &f, 4);
- write(fd, &c, 4);
- size_t Bpp = bytesPerPixel(f);
- for (size_t y=0 ; y<h ; y++) {
- write(fd, base, w*Bpp);
- base = (void *)((char *)base + s*Bpp);
- }
+ result = outBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
+
+ if (base == NULL) {
+ close(fd);
+ _exit(1);
+ }
+
+ w = outBuffer->getWidth();
+ h = outBuffer->getHeight();
+ s = outBuffer->getStride();
+ f = outBuffer->getPixelFormat();
+ d = HAL_DATASPACE_UNKNOWN;
+ size = s * h * bytesPerPixel(f);
+
+ if (png) {
+ const SkImageInfo info =
+ SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType, dataSpaceToColorSpace(d));
+ SkPixmap pixmap(info, base, s * bytesPerPixel(f));
+ struct FDWStream final : public SkWStream {
+ size_t fBytesWritten = 0;
+ int fFd;
+ FDWStream(int f) : fFd(f) {}
+ size_t bytesWritten() const override { return fBytesWritten; }
+ bool write(const void* buffer, size_t size) override {
+ fBytesWritten += size;
+ return size == 0 || ::write(fFd, buffer, size) > 0;
+ }
+ } fdStream(fd);
+ (void)SkEncodeImage(&fdStream, pixmap, SkEncodedImageFormat::kPNG, 100);
+ if (fn != NULL) {
+ notifyMediaScanner(fn);
+ }
+ } else {
+ uint32_t c = dataSpaceToInt(d);
+ write(fd, &w, 4);
+ write(fd, &h, 4);
+ write(fd, &f, 4);
+ write(fd, &c, 4);
+ size_t Bpp = bytesPerPixel(f);
+ for (size_t y=0 ; y<h ; y++) {
+ write(fd, base, w*Bpp);
+ base = (void *)((char *)base + s*Bpp);
}
}
close(fd);
@@ -253,4 +258,4 @@
// b/36066697: Avoid running static destructors.
_exit(0);
-}
+}
\ No newline at end of file
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 1f15c5e..337aeaa 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -161,12 +161,14 @@
tests/LogEntryMatcher_test.cpp \
tests/LogReader_test.cpp \
tests/MetricsManager_test.cpp \
+ tests/StatsLogProcessor_test.cpp \
tests/UidMap_test.cpp \
tests/condition/CombinationConditionTracker_test.cpp \
tests/condition/SimpleConditionTracker_test.cpp \
tests/metrics/OringDurationTracker_test.cpp \
tests/metrics/MaxDurationTracker_test.cpp \
tests/metrics/CountMetricProducer_test.cpp \
+ tests/metrics/DurationMetricProducer_test.cpp \
tests/metrics/EventMetricProducer_test.cpp \
tests/metrics/ValueMetricProducer_test.cpp \
tests/guardrail/StatsdStats_test.cpp
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 2690c7e..2df0c90 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -75,10 +75,8 @@
void StatsLogProcessor::onAnomalyAlarmFired(
const uint64_t timestampNs,
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> anomalySet) {
- for (const auto& anomaly : anomalySet) {
- for (const auto& itr : mMetricsManagers) {
- itr.second->onAnomalyAlarmFired(timestampNs, anomaly);
- }
+ for (const auto& itr : mMetricsManagers) {
+ itr.second->onAnomalyAlarmFired(timestampNs, anomalySet);
}
}
@@ -88,7 +86,7 @@
// pass the event to metrics managers.
for (auto& pair : mMetricsManagers) {
pair.second->onLogEvent(msg);
- flushIfNecessary(msg.GetTimestampNs(), pair.first, pair.second);
+ flushIfNecessary(msg.GetTimestampNs(), pair.first, *(pair.second));
}
// Hard-coded logic to update the isolated uid's in the uid-map.
@@ -201,6 +199,7 @@
iter.rp()->move(toRead);
}
}
+ StatsdStats::getInstance().noteMetricsReportSent(key);
}
void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
@@ -216,16 +215,32 @@
mLastBroadcastTimes.erase(key);
}
-void StatsLogProcessor::flushIfNecessary(uint64_t timestampNs,
- const ConfigKey& key,
- const unique_ptr<MetricsManager>& metricsManager) {
+void StatsLogProcessor::flushIfNecessary(uint64_t timestampNs, const ConfigKey& key,
+ MetricsManager& metricsManager) {
std::lock_guard<std::mutex> lock(mBroadcastTimesMutex);
- size_t totalBytes = metricsManager->byteSize();
- if (totalBytes > .9 * kMaxSerializedBytes) { // Send broadcast so that receivers can pull data.
- auto lastFlushNs = mLastBroadcastTimes.find(key);
- if (lastFlushNs != mLastBroadcastTimes.end()) {
- if (timestampNs - lastFlushNs->second < kMinBroadcastPeriod) {
+ auto lastCheckTime = mLastByteSizeTimes.find(key);
+ if (lastCheckTime != mLastByteSizeTimes.end()) {
+ if (timestampNs - lastCheckTime->second < StatsdStats::kMinByteSizeCheckPeriodNs) {
+ return;
+ }
+ }
+
+ // We suspect that the byteSize() computation is expensive, so we set a rate limit.
+ size_t totalBytes = metricsManager.byteSize();
+ mLastByteSizeTimes[key] = timestampNs;
+ if (totalBytes >
+ StatsdStats::kMaxMetricsBytesPerConfig) { // Too late. We need to start clearing data.
+ // We ignore the return value so we force each metric producer to clear its contents.
+ metricsManager.onDumpReport();
+ StatsdStats::getInstance().noteDataDropped(key);
+ VLOG("StatsD had to toss out metrics for %s", key.ToString().c_str());
+ } else if (totalBytes > .9 * StatsdStats::kMaxMetricsBytesPerConfig) {
+ // Send broadcast so that receivers can pull data.
+ auto lastBroadcastTime = mLastBroadcastTimes.find(key);
+ if (lastBroadcastTime != mLastBroadcastTimes.end()) {
+ if (timestampNs - lastBroadcastTime->second < StatsdStats::kMinBroadcastPeriodNs) {
+ VLOG("StatsD would've sent a broadcast but the rate limit stopped us.");
return;
}
}
@@ -233,11 +248,6 @@
VLOG("StatsD requesting broadcast for %s", key.ToString().c_str());
mSendBroadcast(key);
StatsdStats::getInstance().noteBroadcastSent(key);
- } else if (totalBytes > kMaxSerializedBytes) { // Too late. We need to start clearing data.
- // We ignore the return value so we force each metric producer to clear its contents.
- metricsManager->onDumpReport();
- StatsdStats::getInstance().noteDataDrop(key);
- VLOG("StatsD had to toss out metrics for %s", key.ToString().c_str());
}
}
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 57928d0..a4df23a 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -36,7 +36,7 @@
const std::function<void(const ConfigKey&)>& sendBroadcast);
virtual ~StatsLogProcessor();
- virtual void OnLogEvent(const LogEvent& event);
+ void OnLogEvent(const LogEvent& event);
void OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config);
void OnConfigRemoved(const ConfigKey& key);
@@ -44,6 +44,8 @@
size_t GetMetricsSize(const ConfigKey& key) const;
void onDumpReport(const ConfigKey& key, vector<uint8_t>* outData);
+
+ /* Tells MetricsManager that the alarms in anomalySet have fired. Modifies anomalySet. */
void onAnomalyAlarmFired(
const uint64_t timestampNs,
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> anomalySet);
@@ -58,29 +60,25 @@
std::unordered_map<ConfigKey, long> mLastBroadcastTimes;
+ // Tracks when we last checked the bytes consumed for each config key.
+ std::unordered_map<ConfigKey, long> mLastByteSizeTimes;
+
sp<UidMap> mUidMap; // Reference to the UidMap to lookup app name and version for each uid.
sp<AnomalyMonitor> mAnomalyMonitor;
- /* Max *serialized* size of the logs kept in memory before flushing through binder call.
- Proto lite does not implement the SpaceUsed() function which gives the in memory byte size.
- So we cap memory usage by limiting the serialized size. Note that protobuf's in memory size
- is higher than its serialized size.
- */
- static const size_t kMaxSerializedBytes = 16 * 1024;
-
/* Check if we should send a broadcast if approaching memory limits and if we're over, we
* actually delete the data. */
- void flushIfNecessary(uint64_t timestampNs,
- const ConfigKey& key,
- const unique_ptr<MetricsManager>& metricsManager);
+ void flushIfNecessary(uint64_t timestampNs, const ConfigKey& key,
+ MetricsManager& metricsManager);
// Function used to send a broadcast so that receiver for the config key can call getData
// to retrieve the stored data.
std::function<void(const ConfigKey& key)> mSendBroadcast;
- /* Minimum period between two broadcasts in nanoseconds. Currently set to 60 seconds. */
- static const unsigned long long kMinBroadcastPeriod = 60 * NS_PER_SEC;
+ FRIEND_TEST(StatsLogProcessorTest, TestRateLimitByteSize);
+ FRIEND_TEST(StatsLogProcessorTest, TestRateLimitBroadcast);
+ FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge);
};
} // namespace statsd
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 8b64f0d..dc12efb 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define DEBUG true
+#define DEBUG true // STOPSHIP if true
#include "Log.h"
#include "StatsService.h"
@@ -72,7 +72,7 @@
// ======================================================================
StatsService::StatsService(const sp<Looper>& handlerLooper)
- : mAnomalyMonitor(new AnomalyMonitor(2)) // TODO: Put this comment somewhere better
+ : mAnomalyMonitor(new AnomalyMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS))
{
mUidMap = new UidMap();
mConfigManager = new ConfigManager();
@@ -80,10 +80,10 @@
sp<IStatsCompanionService> sc = getStatsCompanionService();
auto receiver = mConfigManager->GetConfigReceiver(key);
if (sc == nullptr) {
- ALOGD("Could not find StatsCompanionService");
+ VLOG("Could not find StatsCompanionService");
} else if (receiver.first.size() == 0) {
- ALOGD("Statscompanion could not find a broadcast receiver for %s",
- key.ToString().c_str());
+ VLOG("Statscompanion could not find a broadcast receiver for %s",
+ key.ToString().c_str());
} else {
sc->sendBroadcast(String16(receiver.first.c_str()),
String16(receiver.second.c_str()));
@@ -226,10 +226,6 @@
return cmd_print_stats(out, args);
}
- if (!args[0].compare(String8("clear-config"))) {
- return cmd_remove_config_files(out);
- }
-
if (!args[0].compare(String8("meminfo"))) {
return cmd_dump_memory_info(out);
}
@@ -263,11 +259,6 @@
fprintf(out, " Prints the UID, app name, version mapping.\n");
fprintf(out, "\n");
fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmd stats clear-config \n");
- fprintf(out, "\n");
- fprintf(out, " Removes all configs from disk.\n");
- fprintf(out, "\n");
- fprintf(out, "\n");
fprintf(out, "usage: adb shell cmd stats pull-source [int] \n");
fprintf(out, "\n");
fprintf(out, " Prints the output of a pulled metrics source (int indicates source)\n");
@@ -278,24 +269,28 @@
fprintf(out, " Flushes all data on memory to disk.\n");
fprintf(out, "\n");
fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmd stats config remove [UID] NAME\n");
+ fprintf(out, "usage: adb shell cmd stats config remove [UID] [NAME]\n");
fprintf(out, "usage: adb shell cmd stats config update [UID] NAME\n");
fprintf(out, "\n");
fprintf(out, " Adds, updates or removes a configuration. The proto should be in\n");
- fprintf(out, " wire-encoded protobuf format and passed via stdin.\n");
+ fprintf(out, " wire-encoded protobuf format and passed via stdin. If no UID and name is\n");
+ fprintf(out, " provided, then all configs will be removed from memory and disk.\n");
fprintf(out, "\n");
fprintf(out, " UID The uid to use. It is only possible to pass the UID\n");
- fprintf(out, " parameter on eng builds. If UID is omitted the calling\n");
+ fprintf(out, " parameter on eng builds. If UID is omitted the calling\n");
fprintf(out, " uid is used.\n");
fprintf(out, " NAME The per-uid name to use\n");
fprintf(out, "\n");
+ fprintf(out, "\n *Note: If both UID and NAME are omitted then all configs will\n");
+ fprintf(out, "\n be removed from memory and disk!\n");
fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmd stats dump-report [UID] NAME\n");
+ fprintf(out, "usage: adb shell cmd stats dump-report [UID] NAME [--proto]\n");
fprintf(out, " Dump all metric data for a configuration.\n");
fprintf(out, " UID The uid of the configuration. It is only possible to pass\n");
fprintf(out, " the UID parameter on eng builds. If UID is omitted the\n");
fprintf(out, " calling uid is used.\n");
fprintf(out, " NAME The name of the configuration\n");
+ fprintf(out, " --proto Print proto binary.\n");
fprintf(out, "\n");
fprintf(out, "\n");
fprintf(out, "usage: adb shell cmd stats send-broadcast [UID] NAME\n");
@@ -349,10 +344,10 @@
sp<IStatsCompanionService> sc = getStatsCompanionService();
if (sc != nullptr) {
sc->sendBroadcast(String16(receiver.first.c_str()), String16(receiver.second.c_str()));
- ALOGD("StatsService::trigger broadcast succeeded to %s, %s", args[1].c_str(),
- args[2].c_str());
+ VLOG("StatsService::trigger broadcast succeeded to %s, %s", args[1].c_str(),
+ args[2].c_str());
} else {
- ALOGD("Could not access statsCompanion");
+ VLOG("Could not access statsCompanion");
}
return NO_ERROR;
@@ -416,8 +411,12 @@
// Add / update the config.
mConfigManager->UpdateConfig(ConfigKey(uid, name), config);
} else {
- // Remove the config.
- mConfigManager->RemoveConfig(ConfigKey(uid, name));
+ if (argCount == 2) {
+ cmd_remove_all_configs(out);
+ } else {
+ // Remove the config.
+ mConfigManager->RemoveConfig(ConfigKey(uid, name));
+ }
}
return NO_ERROR;
@@ -429,10 +428,15 @@
status_t StatsService::cmd_dump_report(FILE* out, FILE* err, const Vector<String8>& args) {
if (mProcessor != nullptr) {
- const int argCount = args.size();
+ int argCount = args.size();
bool good = false;
+ bool proto = false;
int uid;
string name;
+ if (!std::strcmp("--proto", args[argCount-1].c_str())) {
+ proto = true;
+ argCount -= 1;
+ }
if (argCount == 2) {
// Automatically pick the UID
uid = IPCThreadState::self()->getCallingUid();
@@ -462,8 +466,14 @@
vector<uint8_t> data;
mProcessor->onDumpReport(ConfigKey(uid, name), &data);
// TODO: print the returned StatsLogReport to file instead of printing to logcat.
- fprintf(out, "Dump report for Config [%d,%s]\n", uid, name.c_str());
- fprintf(out, "See the StatsLogReport in logcat...\n");
+ if (proto) {
+ for (size_t i = 0; i < data.size(); i ++) {
+ fprintf(out, "%c", data[i]);
+ }
+ } else {
+ fprintf(out, "Dump report for Config [%d,%s]\n", uid, name.c_str());
+ fprintf(out, "See the StatsLogReport in logcat...\n");
+ }
return android::OK;
} else {
// If arg parsing failed, print the help text and return an error.
@@ -482,13 +492,13 @@
fprintf(out, "Config %s uses %zu bytes\n", key.ToString().c_str(),
mProcessor->GetMetricsSize(key));
}
- fprintf(out, "Detailed statsd stats in logcat...");
+ fprintf(out, "Detailed statsd stats in logcat...\n");
StatsdStats& statsdStats = StatsdStats::getInstance();
bool reset = false;
if (args.size() > 1) {
reset = strtol(args[1].string(), NULL, 10);
}
- vector<int8_t> output;
+ vector<uint8_t> output;
statsdStats.dumpStats(&output, reset);
return NO_ERROR;
}
@@ -526,8 +536,10 @@
return UNKNOWN_ERROR;
}
-status_t StatsService::cmd_remove_config_files(FILE* out) {
- fprintf(out, "Trying to remove config files...\n");
+status_t StatsService::cmd_remove_all_configs(FILE* out) {
+ fprintf(out, "Removing all configs...\n");
+ VLOG("StatsService::cmd_remove_all_configs was called");
+ mConfigManager->RemoveAllConfigs();
StorageManager::deleteAllFiles(STATS_SERVICE_DIR);
return NO_ERROR;
}
@@ -539,9 +551,9 @@
return NO_ERROR;
}
-Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
+Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int64_t>& version,
const vector<String16>& app) {
- if (DEBUG) ALOGD("StatsService::informAllUidData was called");
+ VLOG("StatsService::informAllUidData was called");
if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
return Status::fromExceptionCode(Status::EX_SECURITY,
@@ -549,13 +561,13 @@
}
mUidMap->updateMap(uid, version, app);
- if (DEBUG) ALOGD("StatsService::informAllUidData succeeded");
+ VLOG("StatsService::informAllUidData succeeded");
return Status::ok();
}
-Status StatsService::informOnePackage(const String16& app, int32_t uid, int32_t version) {
- if (DEBUG) ALOGD("StatsService::informOnePackage was called");
+Status StatsService::informOnePackage(const String16& app, int32_t uid, int64_t version) {
+ VLOG("StatsService::informOnePackage was called");
if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
return Status::fromExceptionCode(Status::EX_SECURITY,
@@ -566,7 +578,7 @@
}
Status StatsService::informOnePackageRemoved(const String16& app, int32_t uid) {
- if (DEBUG) ALOGD("StatsService::informOnePackageRemoved was called");
+ VLOG("StatsService::informOnePackageRemoved was called");
if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
return Status::fromExceptionCode(Status::EX_SECURITY,
@@ -577,24 +589,23 @@
}
Status StatsService::informAnomalyAlarmFired() {
- if (DEBUG) ALOGD("StatsService::informAnomalyAlarmFired was called");
+ VLOG("StatsService::informAnomalyAlarmFired was called");
if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
return Status::fromExceptionCode(Status::EX_SECURITY,
"Only system uid can call informAnomalyAlarmFired");
}
- if (DEBUG) ALOGD("StatsService::informAnomalyAlarmFired succeeded");
- // TODO: check through all counters/timers and see if an anomaly has indeed occurred.
- uint64_t currentTimeNs = time(nullptr) * NS_PER_SEC;
+ VLOG("StatsService::informAnomalyAlarmFired succeeded");
+ uint64_t currentTimeSec = time(nullptr);
std::unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> anomalySet =
- mAnomalyMonitor->onAlarmFired(currentTimeNs);
- mProcessor->onAnomalyAlarmFired(currentTimeNs, anomalySet);
+ mAnomalyMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
+ mProcessor->onAnomalyAlarmFired(currentTimeSec * NS_PER_SEC, anomalySet);
return Status::ok();
}
Status StatsService::informPollAlarmFired() {
- if (DEBUG) ALOGD("StatsService::informPollAlarmFired was called");
+ VLOG("StatsService::informPollAlarmFired was called");
if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
return Status::fromExceptionCode(Status::EX_SECURITY,
@@ -603,7 +614,7 @@
mStatsPullerManager.OnAlarmFired();
- if (DEBUG) ALOGD("StatsService::informPollAlarmFired succeeded");
+ VLOG("StatsService::informPollAlarmFired succeeded");
return Status::ok();
}
@@ -615,7 +626,7 @@
}
// When system_server is up and running, schedule the dropbox task to run.
- ALOGD("StatsService::systemRunning");
+ VLOG("StatsService::systemRunning");
sayHiToStatsCompanion();
@@ -628,7 +639,7 @@
"Only system uid can call systemRunning");
}
- ALOGD("StatsService::writeDataToDisk");
+ VLOG("StatsService::writeDataToDisk");
mProcessor->WriteDataToDisk();
@@ -640,10 +651,10 @@
// purposes.
sp<IStatsCompanionService> statsCompanion = getStatsCompanionService();
if (statsCompanion != nullptr) {
- if (DEBUG) ALOGD("Telling statsCompanion that statsd is ready");
+ VLOG("Telling statsCompanion that statsd is ready");
statsCompanion->statsdReady();
} else {
- if (DEBUG) ALOGD("Could not access statsCompanion");
+ VLOG("Could not access statsCompanion");
}
}
@@ -663,7 +674,7 @@
}
Status StatsService::statsCompanionReady() {
- if (DEBUG) ALOGD("StatsService::statsCompanionReady was called");
+ VLOG("StatsService::statsCompanionReady was called");
if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
return Status::fromExceptionCode(Status::EX_SECURITY,
@@ -676,7 +687,7 @@
Status::EX_NULL_POINTER,
"statscompanion unavailable despite it contacting statsd!");
}
- if (DEBUG) ALOGD("StatsService::statsCompanionReady linking to statsCompanion.");
+ VLOG("StatsService::statsCompanionReady linking to statsCompanion.");
IInterface::asBinder(statsCompanion)->linkToDeath(new CompanionDeathRecipient(mAnomalyMonitor));
mAnomalyMonitor->setStatsCompanionService(statsCompanion);
@@ -693,8 +704,7 @@
Status StatsService::getData(const String16& key, vector<uint8_t>* output) {
IPCThreadState* ipc = IPCThreadState::self();
- ALOGD("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(),
- ipc->getCallingUid());
+ VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
if (checkCallingPermission(String16(kPermissionDump))) {
string keyStr = string(String8(key).string());
ConfigKey configKey(ipc->getCallingUid(), keyStr);
@@ -705,6 +715,18 @@
}
}
+Status StatsService::getMetadata(vector<uint8_t>* output) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ VLOG("StatsService::getMetadata with Pid %i, Uid %i", ipc->getCallingPid(),
+ ipc->getCallingUid());
+ if (checkCallingPermission(String16(kPermissionDump))) {
+ StatsdStats::getInstance().dumpStats(output, false); // Don't reset the counters.
+ return Status::ok();
+ } else {
+ return Status::fromExceptionCode(binder::Status::EX_SECURITY);
+ }
+}
+
Status StatsService::addConfiguration(const String16& key,
const vector <uint8_t>& config,
const String16& package, const String16& cls,
@@ -721,6 +743,7 @@
*success = true;
return Status::ok();
} else {
+ *success = false;
return Status::fromExceptionCode(binder::Status::EX_SECURITY);
}
}
@@ -730,6 +753,7 @@
if (checkCallingPermission(String16(kPermissionDump))) {
string keyStr = string(String8(key).string());
mConfigManager->RemoveConfig(ConfigKey(ipc->getCallingUid(), keyStr));
+ *success = true;
return Status::ok();
} else {
*success = false;
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index a32595a..e434f65 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -46,6 +46,10 @@
StatsService(const sp<Looper>& handlerLooper);
virtual ~StatsService();
+ /** The anomaly alarm registered with AlarmManager won't be updated by less than this. */
+ // TODO: Consider making this configurable. And choose a good number.
+ const uint32_t MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS = 5;
+
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
virtual status_t dump(int fd, const Vector<String16>& args);
virtual status_t command(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
@@ -54,9 +58,9 @@
virtual Status statsCompanionReady();
virtual Status informAnomalyAlarmFired();
virtual Status informPollAlarmFired();
- virtual Status informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
+ virtual Status informAllUidData(const vector<int32_t>& uid, const vector<int64_t>& version,
const vector<String16>& app);
- virtual Status informOnePackage(const String16& app, int32_t uid, int32_t version);
+ virtual Status informOnePackage(const String16& app, int32_t uid, int64_t version);
virtual Status informOnePackageRemoved(const String16& app, int32_t uid);
virtual Status writeDataToDisk();
@@ -76,6 +80,11 @@
virtual Status getData(const String16& key, vector<uint8_t>* output) override;
/**
+ * Binder call for clients to get metadata across all configs in statsd.
+ */
+ virtual Status getMetadata(vector<uint8_t>* output) override;
+
+ /**
* Binder call to let clients send a configuration and indicate they're interested when they
* should requestData for this configuration.
*/
@@ -162,9 +171,9 @@
status_t cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args);
/**
- * Removes all configs stored on disk.
+ * Removes all configs stored on disk and on memory.
*/
- status_t cmd_remove_config_files(FILE* out);
+ status_t cmd_remove_all_configs(FILE* out);
/*
* Dump memory usage by statsd.
diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.cpp b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
index da52a9d..4912648 100644
--- a/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
@@ -18,6 +18,7 @@
#include "Log.h"
#include "anomaly/AnomalyMonitor.h"
+#include "guardrail/StatsdStats.h"
namespace android {
namespace os {
@@ -72,13 +73,11 @@
return;
}
if (DEBUG) ALOGD("Removing alarm with time %u", alarm->timestampSec);
- mPq.remove(alarm);
+ bool wasPresent = mPq.remove(alarm);
+ if (!wasPresent) return;
if (mPq.empty()) {
if (DEBUG) ALOGD("Queue is empty. Cancel any alarm.");
- mRegisteredAlarmTimeSec = 0;
- if (mStatsCompanionService != nullptr) {
- mStatsCompanionService->cancelAnomalyAlarm();
- }
+ cancelRegisteredAlarmTime_l();
return;
}
uint32_t soonestAlarmTimeSec = mPq.top()->timestampSec;
@@ -105,10 +104,7 @@
if (!oldAlarms.empty()) {
if (mPq.empty()) {
if (DEBUG) ALOGD("Queue is empty. Cancel any alarm.");
- mRegisteredAlarmTimeSec = 0;
- if (mStatsCompanionService != nullptr) {
- mStatsCompanionService->cancelAnomalyAlarm();
- }
+ cancelRegisteredAlarmTime_l();
} else {
// Always update the registered alarm in this case (unlike remove()).
updateRegisteredAlarmTime_l(mPq.top()->timestampSec);
@@ -122,6 +118,16 @@
mRegisteredAlarmTimeSec = timestampSec;
if (mStatsCompanionService != nullptr) {
mStatsCompanionService->setAnomalyAlarm(secToMs(mRegisteredAlarmTimeSec));
+ StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
+ }
+}
+
+void AnomalyMonitor::cancelRegisteredAlarmTime_l() {
+ if (DEBUG) ALOGD("Cancelling reg alarm.");
+ mRegisteredAlarmTimeSec = 0;
+ if (mStatsCompanionService != nullptr) {
+ mStatsCompanionService->cancelAnomalyAlarm();
+ StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
}
}
@@ -129,11 +135,6 @@
return ((int64_t)timeSec) * 1000;
}
-unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> AnomalyMonitor::onAlarmFired(
- uint64_t timestampNs) {
- return popSoonerThan(static_cast<uint32_t>(timestampNs));
-}
-
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.h b/cmds/statsd/src/anomaly/AnomalyMonitor.h
index 0bd5055..7acc7904 100644
--- a/cmds/statsd/src/anomaly/AnomalyMonitor.h
+++ b/cmds/statsd/src/anomaly/AnomalyMonitor.h
@@ -23,7 +23,6 @@
#include <queue>
#include <set>
-#include <unordered_map>
#include <unordered_set>
#include <vector>
@@ -97,15 +96,6 @@
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> popSoonerThan(
uint32_t timestampSec);
- // TODO: Function that uses popSoonerThan to get all alarms that have fired, and then
- // iterates over all DurationAnomalyTracker, looking for those alarms. When they're found,
- // have them declareAnomaly on those alarms. This means that DurationAnomalyTracker
- // must be thread-safe (since this is being called on a different thread). There is no
- // worry about missing the alarms (due to them being cancelled after this function being called)
- // because DurationAnomalyTracker guarantees that it checks for anaomlies when it cancels
- // alarms anyway.
- // void declareAnomalies(uint32_t timestampSec);
-
/**
* Returns the projected alarm timestamp that is registered with
* StatsCompanionService. This may not be equal to the soonest alarm,
@@ -115,8 +105,6 @@
return mRegisteredAlarmTimeSec;
}
- unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> onAlarmFired(uint64_t timestampNs);
-
private:
std::mutex mLock;
@@ -150,6 +138,12 @@
*/
void updateRegisteredAlarmTime_l(uint32_t timestampSec);
+ /**
+ * Cancels the alarm registered with StatsCompanionService.
+ * Also correspondingly sets mRegisteredAlarmTimeSec to 0.
+ */
+ void cancelRegisteredAlarmTime_l();
+
/** Converts uint32 timestamp in seconds to a Java long in msec. */
int64_t secToMs(uint32_t timeSec);
};
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index 0904a04..e8b4083 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -18,33 +18,35 @@
#include "Log.h"
#include "AnomalyTracker.h"
+#include "guardrail/StatsdStats.h"
+#include <android/os/IIncidentManager.h>
+#include <android/os/IncidentReportArgs.h>
+#include <binder/IServiceManager.h>
#include <time.h>
namespace android {
namespace os {
namespace statsd {
-AnomalyTracker::AnomalyTracker(const Alert& alert, const int64_t& bucketSizeNs)
+// TODO: Separate DurationAnomalyTracker as a separate subclass and let each MetricProducer
+// decide and let which one it wants.
+// TODO: Get rid of bucketNumbers, and return to the original circular array method.
+AnomalyTracker::AnomalyTracker(const Alert& alert, const ConfigKey& configKey)
: mAlert(alert),
- mBucketSizeNs(bucketSizeNs),
- mNumOfPastPackets(mAlert.number_of_buckets() - 1) {
+ mConfigKey(configKey),
+ mNumOfPastBuckets(mAlert.number_of_buckets() - 1) {
VLOG("AnomalyTracker() called");
if (mAlert.number_of_buckets() <= 0) {
- ALOGE("Cannot create DiscreteAnomalyTracker with %lld buckets",
+ ALOGE("Cannot create AnomalyTracker with %lld buckets",
(long long)mAlert.number_of_buckets());
return;
}
- if (mBucketSizeNs <= 0) {
- ALOGE("Cannot create DiscreteAnomalyTracker with bucket size %lld ",
- (long long)mBucketSizeNs);
- return;
- }
if (!mAlert.has_trigger_if_sum_gt()) {
- ALOGE("Cannot create DiscreteAnomalyTracker without threshold");
+ ALOGE("Cannot create AnomalyTracker without threshold");
return;
}
- reset(); // initialization
+ resetStorage(); // initialization
}
AnomalyTracker::~AnomalyTracker() {
@@ -52,37 +54,36 @@
stopAllAlarms();
}
-void AnomalyTracker::reset() {
- VLOG("reset() called.");
- stopAllAlarms();
+void AnomalyTracker::resetStorage() {
+ VLOG("resetStorage() called.");
mPastBuckets.clear();
// Excludes the current bucket.
- mPastBuckets.resize(mNumOfPastPackets);
+ mPastBuckets.resize(mNumOfPastBuckets);
mSumOverPastBuckets.clear();
- mMostRecentBucketNum = -1;
- mLastAlarmTimestampNs = -1;
+
+ if (!mAlarms.empty()) VLOG("AnomalyTracker.resetStorage() called but mAlarms is NOT empty!");
}
size_t AnomalyTracker::index(int64_t bucketNum) const {
- return bucketNum % mNumOfPastPackets;
+ return bucketNum % mNumOfPastBuckets;
}
void AnomalyTracker::flushPastBuckets(const int64_t& latestPastBucketNum) {
VLOG("addPastBucket() called.");
- if (latestPastBucketNum <= mMostRecentBucketNum - mNumOfPastPackets) {
+ if (latestPastBucketNum <= mMostRecentBucketNum - mNumOfPastBuckets) {
ALOGE("Cannot add a past bucket %lld units in past", (long long)latestPastBucketNum);
return;
}
// The past packets are ancient. Empty out old mPastBuckets[i] values and reset
// mSumOverPastBuckets.
- if (latestPastBucketNum - mMostRecentBucketNum >= mNumOfPastPackets) {
+ if (latestPastBucketNum - mMostRecentBucketNum >= mNumOfPastBuckets) {
mPastBuckets.clear();
- mPastBuckets.resize(mNumOfPastPackets);
+ mPastBuckets.resize(mNumOfPastBuckets);
mSumOverPastBuckets.clear();
} else {
- for (int64_t i = std::max(0LL, (long long)(mMostRecentBucketNum - mNumOfPastPackets + 1));
- i <= latestPastBucketNum - mNumOfPastPackets; i++) {
+ for (int64_t i = std::max(0LL, (long long)(mMostRecentBucketNum - mNumOfPastBuckets + 1));
+ i <= latestPastBucketNum - mNumOfPastBuckets; i++) {
const int idx = index(i);
subtractBucketFromSum(mPastBuckets[idx]);
mPastBuckets[idx] = nullptr; // release (but not clear) the old bucket.
@@ -91,7 +92,7 @@
// It is an update operation.
if (latestPastBucketNum <= mMostRecentBucketNum &&
- latestPastBucketNum > mMostRecentBucketNum - mNumOfPastPackets) {
+ latestPastBucketNum > mMostRecentBucketNum - mNumOfPastBuckets) {
subtractBucketFromSum(mPastBuckets[index(latestPastBucketNum)]);
}
}
@@ -190,61 +191,81 @@
if (currentBucketNum > mMostRecentBucketNum + 1) {
addPastBucket(key, 0, currentBucketNum - 1);
}
- return getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt();
+ return mAlert.has_trigger_if_sum_gt()
+ && getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt();
}
-void AnomalyTracker::declareAnomaly(const uint64_t& timestamp) {
- if (mLastAlarmTimestampNs >= 0 &&
- timestamp - mLastAlarmTimestampNs <= mAlert.refractory_period_secs() * NS_PER_SEC) {
- VLOG("Skipping anomaly check since within refractory period");
+void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs) {
+ // TODO: This should also take in the const HashableDimensionKey& key, to pass
+ // more details to incidentd and to make mRefractoryPeriodEndsSec key-specific.
+ // TODO: Why receive timestamp? RefractoryPeriod should always be based on real time right now.
+ if (isInRefractoryPeriod(timestampNs)) {
+ VLOG("Skipping anomaly declaration since within refractory period");
return;
}
// TODO(guardrail): Consider guarding against too short refractory periods.
- mLastAlarmTimestampNs = timestamp;
+ mLastAlarmTimestampNs = timestampNs;
+
+
+ // TODO: If we had access to the bucket_size_millis, consider calling resetStorage()
+ // if (mAlert.refractory_period_secs() > mNumOfPastBuckets * bucketSizeNs) { resetStorage(); }
if (mAlert.has_incidentd_details()) {
- // TODO: Can construct a name based on the criteria (and/or relay the criteria).
- ALOGW("An anomaly (nameless) has occurred! Informing incidentd.");
- // TODO: Send incidentd_details.name and incidentd_details.incidentd_sections to incidentd
+ if (mAlert.has_name()) {
+ ALOGW("An anomaly (%s) has occurred! Informing incidentd.",
+ mAlert.name().c_str());
+ } else {
+ // TODO: Can construct a name based on the criteria (and/or relay the criteria).
+ ALOGW("An anomaly (nameless) has occurred! Informing incidentd.");
+ }
+ informIncidentd();
} else {
ALOGW("An anomaly has occurred! (But informing incidentd not requested.)");
}
+
+ StatsdStats::getInstance().noteAnomalyDeclared(mConfigKey, mAlert.name());
}
void AnomalyTracker::declareAnomalyIfAlarmExpired(const HashableDimensionKey& dimensionKey,
- const uint64_t& timestamp) {
+ const uint64_t& timestampNs) {
auto itr = mAlarms.find(dimensionKey);
if (itr == mAlarms.end()) {
return;
}
if (itr->second != nullptr &&
- static_cast<uint32_t>(timestamp / NS_PER_SEC) >= itr->second->timestampSec) {
- declareAnomaly(timestamp);
+ static_cast<uint32_t>(timestampNs / NS_PER_SEC) >= itr->second->timestampSec) {
+ declareAnomaly(timestampNs);
stopAlarm(dimensionKey);
}
}
-void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestamp,
+void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestampNs,
const int64_t& currBucketNum,
const HashableDimensionKey& key,
const int64_t& currentBucketValue) {
if (detectAnomaly(currBucketNum, key, currentBucketValue)) {
- declareAnomaly(timestamp);
+ declareAnomaly(timestampNs);
}
}
-void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestamp,
+void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestampNs,
const int64_t& currBucketNum,
const DimToValMap& currentBucket) {
if (detectAnomaly(currBucketNum, currentBucket)) {
- declareAnomaly(timestamp);
+ declareAnomaly(timestampNs);
}
}
void AnomalyTracker::startAlarm(const HashableDimensionKey& dimensionKey,
- const uint64_t& timestamp) {
- sp<const AnomalyAlarm> alarm = new AnomalyAlarm{static_cast<uint32_t>(timestamp / NS_PER_SEC)};
+ const uint64_t& timestampNs) {
+ uint32_t timestampSec = static_cast<uint32_t>(timestampNs / NS_PER_SEC);
+ if (isInRefractoryPeriod(timestampNs)) {
+ VLOG("Skipping setting anomaly alarm since it'd fall in the refractory period");
+ return;
+ }
+
+ sp<const AnomalyAlarm> alarm = new AnomalyAlarm{timestampSec};
mAlarms.insert({dimensionKey, alarm});
if (mAnomalyMonitor != nullptr) {
mAnomalyMonitor->add(alarm);
@@ -255,9 +276,9 @@
auto itr = mAlarms.find(dimensionKey);
if (itr != mAlarms.end()) {
mAlarms.erase(dimensionKey);
- }
- if (mAnomalyMonitor != nullptr) {
- mAnomalyMonitor->remove(itr->second);
+ if (mAnomalyMonitor != nullptr) {
+ mAnomalyMonitor->remove(itr->second);
+ }
}
}
@@ -271,6 +292,58 @@
}
}
+bool AnomalyTracker::isInRefractoryPeriod(const uint64_t& timestampNs) {
+ return mLastAlarmTimestampNs >= 0 &&
+ timestampNs - mLastAlarmTimestampNs <= mAlert.refractory_period_secs() * NS_PER_SEC;
+}
+
+void AnomalyTracker::informAlarmsFired(const uint64_t& timestampNs,
+ unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) {
+
+ if (firedAlarms.empty() || mAlarms.empty()) return;
+ // Find the intersection of firedAlarms and mAlarms.
+ // The for loop is inefficient, since it loops over all keys, but that's okay since it is very
+ // seldomly called. The alternative would be having AnomalyAlarms store information about the
+ // AnomalyTracker and key, but that's a lot of data overhead to speed up something that is
+ // rarely ever called.
+ unordered_map<HashableDimensionKey, sp<const AnomalyAlarm>> matchedAlarms;
+ for (const auto& kv : mAlarms) {
+ if (firedAlarms.count(kv.second) > 0) {
+ matchedAlarms.insert({kv.first, kv.second});
+ }
+ }
+
+ // Now declare each of these alarms to have fired.
+ for (const auto& kv : matchedAlarms) {
+ declareAnomaly(timestampNs /* TODO: , kv.first */);
+ mAlarms.erase(kv.first);
+ firedAlarms.erase(kv.second); // No one else can also own it, so we're done with it.
+ }
+}
+
+void AnomalyTracker::informIncidentd() {
+ VLOG("informIncidentd called.");
+ if (!mAlert.has_incidentd_details()) {
+ ALOGE("Attempted to call incidentd without any incidentd_details.");
+ return;
+ }
+ sp<IIncidentManager> service = interface_cast<IIncidentManager>(
+ defaultServiceManager()->getService(android::String16("incident")));
+ if (service == NULL) {
+ ALOGW("Couldn't get the incident service.");
+ return;
+ }
+
+ IncidentReportArgs incidentReport;
+ const Alert::IncidentdDetails& details = mAlert.incidentd_details();
+ for (int i = 0; i < details.section_size(); i++) {
+ incidentReport.addSection(details.section(i));
+ }
+ // TODO: Pass in mAlert.name() into the addHeader?
+
+ service->reportIncident(incidentReport);
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index ce6c995..874add2 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -18,6 +18,7 @@
#include <gtest/gtest_prod.h>
#include "AnomalyMonitor.h"
+#include "config/ConfigKey.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert
#include "stats_util.h" // HashableDimensionKey and DimToValMap
@@ -32,10 +33,10 @@
using std::unordered_map;
using std::shared_ptr;
-// This anomaly track assmues that all values are non-negative.
+// Does NOT allow negative values.
class AnomalyTracker : public virtual RefBase {
public:
- AnomalyTracker(const Alert& alert, const int64_t& bucketSizeNs);
+ AnomalyTracker(const Alert& alert, const ConfigKey& configKey);
virtual ~AnomalyTracker();
@@ -51,12 +52,12 @@
const int64_t& currentBucketValue);
// Informs incidentd about the detected alert.
- void declareAnomaly(const uint64_t& timestamp);
+ void declareAnomaly(const uint64_t& timestampNs);
// Detects the alert and informs the incidentd when applicable.
- void detectAndDeclareAnomaly(const uint64_t& timestamp, const int64_t& currBucketNum,
+ void detectAndDeclareAnomaly(const uint64_t& timestampNs, const int64_t& currBucketNum,
const DimToValMap& currentBucket);
- void detectAndDeclareAnomaly(const uint64_t& timestamp, const int64_t& currBucketNum,
+ void detectAndDeclareAnomaly(const uint64_t& timestampNs, const int64_t& currBucketNum,
const HashableDimensionKey& key,
const int64_t& currentBucketValue);
@@ -75,7 +76,7 @@
// Declares the anomaly when the alarm expired given the current timestamp.
void declareAnomalyIfAlarmExpired(const HashableDimensionKey& dimensionKey,
- const uint64_t& timestamp);
+ const uint64_t& timestampNs);
// Helper function to return the sum value of past buckets at given dimension.
int64_t getSumOverPastBuckets(const HashableDimensionKey& key) const;
@@ -93,20 +94,30 @@
return mLastAlarmTimestampNs;
}
- inline int getNumOfPastPackets() const {
- return mNumOfPastPackets;
+ inline int getNumOfPastBuckets() const {
+ return mNumOfPastBuckets;
}
+ // Declares an anomaly for each alarm in firedAlarms that belongs to this AnomalyTracker,
+ // and removes it from firedAlarms. Does NOT remove the alarm from the AnomalyMonitor.
+ // TODO: This will actually be called from a different thread, so make it thread-safe!
+ // TODO: Consider having AnomalyMonitor have a reference to each relevant MetricProducer
+ // instead of calling it from a chain starting at StatsLogProcessor.
+ void informAlarmsFired(const uint64_t& timestampNs,
+ unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms);
+
protected:
void flushPastBuckets(const int64_t& currBucketNum);
+
// statsd_config.proto Alert message that defines this tracker.
const Alert mAlert;
- // Bucket duration in ns.
- int64_t mBucketSizeNs = 0;
+ // A reference to the Alert's config key.
+ const ConfigKey& mConfigKey;
- // The number of past packets to track in the anomaly detection.
- int mNumOfPastPackets = 0;
+ // Number of past buckets. One less than the total number of buckets needed
+ // for the anomaly detection (since the current bucket is not in the past).
+ int mNumOfPastBuckets;
// The alarms owned by this tracker. The alarm monitor also shares the alarm pointers when they
// are still active.
@@ -134,11 +145,16 @@
// and remove any items with value 0.
void subtractBucketFromSum(const shared_ptr<DimToValMap>& bucket);
+ bool isInRefractoryPeriod(const uint64_t& timestampNs);
+
// Calculates the corresponding bucket index within the circular array.
size_t index(int64_t bucketNum) const;
- // Resets all data. For use when all the data gets stale.
- void reset();
+ // Resets all bucket data. For use when all the data gets stale.
+ void resetStorage();
+
+ // Informs the incident service that an anomaly has occurred.
+ void informIncidentd();
FRIEND_TEST(AnomalyTrackerTest, TestConsecutiveBuckets);
FRIEND_TEST(AnomalyTrackerTest, TestSparseBuckets);
diff --git a/cmds/statsd/src/anomaly/indexed_priority_queue.h b/cmds/statsd/src/anomaly/indexed_priority_queue.h
index 4982d4b..99882d0 100644
--- a/cmds/statsd/src/anomaly/indexed_priority_queue.h
+++ b/cmds/statsd/src/anomaly/indexed_priority_queue.h
@@ -37,7 +37,7 @@
/**
* Min priority queue for generic type AA.
* Unlike a regular priority queue, this class is also capable of removing interior elements.
- * @tparam Comparator must implement [bool operator()(sp< AA> a, sp< AA> b)], returning
+ * @tparam Comparator must implement [bool operator()(sp<const AA> a, sp<const AA> b)], returning
* whether a should be closer to the top of the queue than b.
*/
template <class AA, class Comparator>
@@ -46,8 +46,11 @@
indexed_priority_queue();
/** Adds a into the priority queue. If already present or a==nullptr, does nothing. */
void push(sp<const AA> a);
- /** Removes a from the priority queue. If not present or a==nullptr, does nothing. */
- void remove(sp<const AA> a);
+ /*
+ * Removes a from the priority queue. If not present or a==nullptr, does nothing.
+ * Returns true if a had been present (and is now removed), else false.
+ */
+ bool remove(sp<const AA> a);
/** Removes the top element, if there is one. */
void pop();
/** Removes all elements. */
@@ -97,17 +100,17 @@
}
template <class AA, class Comparator>
-void indexed_priority_queue<AA, Comparator>::remove(sp<const AA> a) {
- if (a == nullptr) return;
- if (!contains(a)) return;
+bool indexed_priority_queue<AA, Comparator>::remove(sp<const AA> a) {
+ if (a == nullptr) return false;
+ if (!contains(a)) return false;
size_t idx = indices[a];
if (idx >= pq.size()) {
- return;
+ return false;
}
if (idx == size()) { // if a is the last element, i.e. at index idx == size() == (pq.size()-1)
pq.pop_back();
indices.erase(a);
- return;
+ return true;
}
// move last element (guaranteed not to be at idx) to idx, then delete a
sp<const AA> last_a = pq.back();
@@ -119,6 +122,8 @@
// get the heap back in order (since the element at idx is not in order)
sift_up(idx);
sift_down(idx);
+
+ return true;
}
// The same as, but slightly more efficient than, remove(top()).
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 20e7c60..c81fc1d 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -46,12 +46,14 @@
SyncStateChanged sync_state_changed = 7;
ScheduledJobStateChanged scheduled_job_state_changed = 8;
ScreenBrightnessChanged screen_brightness_changed = 9;
- // 10-20 are temporarily reserved for wakelocks etc.
WakelockStateChanged wakelock_state_changed = 10;
- UidWakelockStateChanged uid_wakelock_state_changed = 11;
- LongPartialWakelockStateChanged long_partial_wakelock_state_changed = 12;
- BatterySaverModeStateChanged battery_saver_mode_state_changed = 21;
- DeviceIdleModeStateChanged device_idle_mode_state_changed = 22;
+ LongPartialWakelockStateChanged long_partial_wakelock_state_changed = 11;
+ MobileRadioPowerStateChanged mobile_radio_power_state_changed = 12;
+ WifiRadioPowerStateChanged wifi_radio_power_state_changed = 13;
+ // TODO: 14-19 are blank, but need not be
+ BatterySaverModeStateChanged battery_saver_mode_state_changed = 20;
+ DeviceIdleModeStateChanged device_idle_mode_state_changed = 21;
+ DeviceIdlingModeStateChanged device_idling_mode_state_changed = 22;
AudioStateChanged audio_state_changed = 23;
MediaCodecActivityChanged media_codec_activity_changed = 24;
CameraStateChanged camera_state_changed = 25;
@@ -91,6 +93,8 @@
CpuTimePerFreqPulled cpu_time_per_freq_pulled = 1008;
CpuTimePerUidPulled cpu_time_per_uid_pulled = 1009;
CpuTimePerUidFreqPulled cpu_time_per_uid_freq_pulled = 1010;
+ WifiActivityEnergyInfoPulled wifi_activity_energy_info_pulled = 1011;
+ ModemActivityInfoPulled modem_activity_info_pulled = 1012;
}
}
@@ -99,7 +103,11 @@
* resulted in a particular bit of work being done.
*/
message WorkSource {
- // TODO
+ // The uid for a given element in the attribution chain.
+ repeated int32 uid = 1;
+ // The (optional) string tag for an element in the attribution chain. If the
+ // element has no tag, it is encoded as an empty string.
+ repeated string tag = 2;
}
/*
@@ -143,6 +151,7 @@
STATE_DOZE = 3;
STATE_DOZE_SUSPEND = 4;
STATE_VR = 5;
+ STATE_ON_SUSPEND = 6;
}
// New screen state.
optional State display_state = 1;
@@ -175,13 +184,17 @@
// TODO: What is this?
optional string name = 2;
- // The state.
- // TODO: Use an enum.
- optional int32 event = 3;
+ // What lifecycle state the process changed to.
+ // This enum is specific to atoms.proto.
+ enum Event {
+ PROCESS_FINISHED = 0;
+ PROCESS_STARTED = 1;
+ PROCESS_CRASHED = 2;
+ PROCESS_ANRED = 3;
+ }
+ optional Event event = 3;
}
-
-
/**
* Logs when the ble scan state changes.
*
@@ -404,38 +417,15 @@
optional string tag = 3;
enum State {
- OFF = 0;
- ON = 1;
+ RELEASE = 0;
+ ACQUIRE = 1;
+ CHANGE_RELEASE = 2;
+ CHANGE_ACQUIRE = 3;
}
optional State state = 4;
}
/**
- * Logs when an app is holding a wakelock, regardless of the wakelock's name.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message UidWakelockStateChanged {
- // TODO: Add attribution instead of uid.
- optional int32 uid = 1;
-
- // Type of wakelock.
- enum Type {
- PARTIAL = 0;
- FULL = 1;
- WINDOW = 2;
- }
- optional Type type = 2;
-
- enum State {
- OFF = 0;
- ON = 1;
- }
- optional State state = 3;
-}
-
-/**
* Logs when a partial wakelock is considered 'long' (over 1 min).
*
* Logged from:
@@ -476,11 +466,33 @@
* Logs Doze mode state change.
*
* Logged from:
- * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
*/
message DeviceIdleModeStateChanged {
// TODO: Use the enum matching BatteryStats.DEVICE_IDLE_MODE_.
- optional int32 state = 1;
+ enum State {
+ DEVICE_IDLE_MODE_OFF = 0;
+ DEVICE_IDLE_MODE_LIGHT = 1;
+ DEVICE_IDLE_MODE_DEEP = 2;
+ }
+ optional State state = 1;
+}
+
+
+/**
+ * Logs state change of Doze mode including maintenance windows.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message DeviceIdlingModeStateChanged {
+ // TODO: Use the enum matching BatteryStats.DEVICE_IDLE_MODE_.
+ enum State {
+ DEVICE_IDLE_MODE_OFF = 0;
+ DEVICE_IDLE_MODE_LIGHT = 1;
+ DEVICE_IDLE_MODE_DEEP = 2;
+ }
+ optional State state = 1;
}
/**
@@ -580,6 +592,49 @@
message WakeupAlarmOccurred {
// TODO: Add attribution instead of uid?
optional int32 uid = 1;
+
+ // Name of the wakeup alarm.
+ optional string tag = 2;
+}
+
+/**
+ * Logs when an an app causes the mobile radio to change state.
+ * Changing from LOW to MEDIUM or HIGH can be considered the app waking the mobile radio.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message MobileRadioPowerStateChanged {
+ // TODO: Add attribution instead of uid?
+ optional int32 uid = 1;
+
+ // TODO: Reference telephony/java/android/telephony/DataConnectionRealTimeInfo.java states.
+ enum PowerState {
+ DC_POWER_STATE_LOW = 1;
+ DC_POWER_STATE_MEDIUM = 2;
+ DC_POWER_STATE_HIGH = 3;
+ }
+ optional PowerState power_state = 2;
+}
+
+/**
+ * Logs when an an app causes the wifi radio to change state.
+ * Changing from LOW to MEDIUM or HIGH can be considered the app waking the wifi radio.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message WifiRadioPowerStateChanged {
+ // TODO: Add attribution instead of uid?
+ optional int32 uid = 1;
+
+ // TODO: Reference telephony/java/android/telephony/DataConnectionRealTimeInfo.java states.
+ enum PowerState {
+ DC_POWER_STATE_LOW = 1;
+ DC_POWER_STATE_MEDIUM = 2;
+ DC_POWER_STATE_HIGH = 3;
+ }
+ optional PowerState power_state = 2;
}
/**
@@ -699,7 +754,7 @@
optional int32 user = 7;
}
-/*
+/**
* Logs activity going to foreground or background
*
* Logged from:
@@ -839,7 +894,7 @@
optional int64 time = 4;
}
-/*
+/**
* Pulls PowerStatePlatformSleepState.
*
* Definition here:
@@ -899,7 +954,7 @@
optional int32 is_create = 3;
}
-/*
+/**
* Pulls Cpu time per frequency.
* Note: this should be pulled for gauge metric only, without condition.
* The puller keeps internal state of last values. It should not be pulled by
@@ -916,7 +971,7 @@
optional uint64 time = 3;
}
-/*
+/**
* Pulls Cpu Time Per Uid.
* Note that isolated process uid time should be attributed to host uids.
*/
@@ -965,3 +1020,56 @@
// The destination port if this was a TCP or UDP packet.
optional int32 destination_port = 9;
}
+
+/**
+ * Pulls Wifi Controller Activity Energy Info
+ */
+message WifiActivityEnergyInfoPulled {
+ // timestamp(wall clock) of record creation
+ optional uint64 timestamp_ms = 1;
+ // stack reported state
+ // TODO: replace this with proto enum
+ optional int32 stack_state = 2;
+ // tx time in ms
+ optional uint64 controller_tx_time_ms = 3;
+ // rx time in ms
+ optional uint64 controller_rx_time_ms = 4;
+ // idle time in ms
+ optional uint64 controller_idle_time_ms = 5;
+ // product of current(mA), voltage(V) and time(ms)
+ optional uint64 controller_energy_used = 6;
+}
+
+/**
+ * Pulls Modem Activity Energy Info
+ */
+message ModemActivityInfoPulled {
+ // timestamp(wall clock) of record creation
+ optional uint64 timestamp_ms = 1;
+ // sleep time in ms.
+ optional uint64 sleep_time_ms = 2;
+ // idle time in ms
+ optional uint64 controller_idle_time_ms = 3;
+ /**
+ * Tx power index
+ * index 0 = tx_power < 0dBm
+ * index 1 = 0dBm < tx_power < 5dBm
+ * index 2 = 5dBm < tx_power < 15dBm
+ * index 3 = 15dBm < tx_power < 20dBm
+ * index 4 = tx_power > 20dBm
+ */
+ // tx time in ms at power level 0
+ optional uint64 controller_tx_time_pl0_ms = 4;
+ // tx time in ms at power level 1
+ optional uint64 controller_tx_time_pl1_ms = 5;
+ // tx time in ms at power level 2
+ optional uint64 controller_tx_time_pl2_ms = 6;
+ // tx time in ms at power level 3
+ optional uint64 controller_tx_time_pl3_ms = 7;
+ // tx time in ms at power level 4
+ optional uint64 controller_tx_time_pl4_ms = 8;
+ // rx time in ms at power level 5
+ optional uint64 controller_rx_time_ms = 9;
+ // product of current(mA), voltage(V) and time(ms)
+ optional uint64 energy_used = 10;
+}
\ No newline at end of file
diff --git a/cmds/statsd/src/atoms_copy.proto b/cmds/statsd/src/atoms_copy.proto
index 58e225a..18b2144 100644
--- a/cmds/statsd/src/atoms_copy.proto
+++ b/cmds/statsd/src/atoms_copy.proto
@@ -99,7 +99,11 @@
* resulted in a particular bit of work being done.
*/
message WorkSource {
- // TODO
+ // The uid for a given element in the attribution chain.
+ repeated int32 uid = 1;
+ // The (optional) string tag for an element in the attribution chain. If the
+ // element has no tag, it is encoded as an empty string.
+ repeated string tag = 2;
}
/*
@@ -404,8 +408,10 @@
optional string tag = 3;
enum State {
- OFF = 0;
- ON = 1;
+ RELEASE = 0;
+ ACQUIRE = 1;
+ CHANGE_RELEASE = 2;
+ CHANGE_ACQUIRE = 3;
}
optional State state = 4;
}
@@ -907,4 +913,4 @@
optional uint64 uid = 1;
optional uint64 freq_idx = 2;
optional uint64 time_ms = 3;
-}
+}
\ No newline at end of file
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
index dd84cf4..02aca1a 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -39,11 +39,11 @@
VLOG("~CombinationConditionTracker() %s", mName.c_str());
}
-bool CombinationConditionTracker::init(const vector<Condition>& allConditionConfig,
+bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConfig,
const vector<sp<ConditionTracker>>& allConditionTrackers,
const unordered_map<string, int>& conditionNameIndexMap,
vector<bool>& stack) {
- VLOG("Combiniation condition init() %s", mName.c_str());
+ VLOG("Combination predicate init() %s", mName.c_str());
if (mInitialized) {
return true;
}
@@ -51,22 +51,22 @@
// mark this node as visited in the recursion stack.
stack[mIndex] = true;
- Condition_Combination combinationCondition = allConditionConfig[mIndex].combination();
+ Predicate_Combination combinationCondition = allConditionConfig[mIndex].combination();
if (!combinationCondition.has_operation()) {
return false;
}
mLogicalOperation = combinationCondition.operation();
- if (mLogicalOperation == LogicalOperation::NOT && combinationCondition.condition_size() != 1) {
+ if (mLogicalOperation == LogicalOperation::NOT && combinationCondition.predicate_size() != 1) {
return false;
}
- for (string child : combinationCondition.condition()) {
+ for (string child : combinationCondition.predicate()) {
auto it = conditionNameIndexMap.find(child);
if (it == conditionNameIndexMap.end()) {
- ALOGW("Condition %s not found in the config", child.c_str());
+ ALOGW("Predicate %s not found in the config", child.c_str());
return false;
}
@@ -154,7 +154,7 @@
}
}
nonSlicedConditionCache[mIndex] = ConditionState::kUnknown;
- ALOGD("CombinationCondition %s sliced may changed? %d", mName.c_str(),
+ ALOGD("CombinationPredicate %s sliced may changed? %d", mName.c_str(),
conditionChangedCache[mIndex] == true);
}
}
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
index 00dc6b7..9336914 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.h
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -30,7 +30,7 @@
~CombinationConditionTracker();
- bool init(const std::vector<Condition>& allConditionConfig,
+ bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
const std::unordered_map<std::string, int>& conditionNameIndexMap,
std::vector<bool>& stack) override;
@@ -47,7 +47,7 @@
private:
LogicalOperation mLogicalOperation;
- // Store index of the children Conditions.
+ // Store index of the children Predicates.
// We don't store string name of the Children, because we want to get rid of the hash map to
// map the name to object. We don't want to store smart pointers to children, because it
// increases the risk of circular dependency and memory leak.
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index b85d8c1..6f66ad6 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -45,12 +45,12 @@
// Initialize this ConditionTracker. This initialization is done recursively (DFS). It can also
// be done in the constructor, but we do it separately because (1) easy to return a bool to
// indicate whether the initialization is successful. (2) makes unit test easier.
- // allConditionConfig: the list of all Condition config from statsd_config.
+ // allConditionConfig: the list of all Predicate config from statsd_config.
// allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also
// need to call init() on children conditions)
// conditionNameIndexMap: the mapping from condition name to its index.
// stack: a bit map to keep track which nodes have been visited on the stack in the recursion.
- virtual bool init(const std::vector<Condition>& allConditionConfig,
+ virtual bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
const std::unordered_map<std::string, int>& conditionNameIndexMap,
std::vector<bool>& stack) = 0;
@@ -118,4 +118,3 @@
} // namespace statsd
} // namespace os
} // namespace android
-
diff --git a/cmds/statsd/src/condition/ConditionWizard.h b/cmds/statsd/src/condition/ConditionWizard.h
index 1a01afa..30a3684 100644
--- a/cmds/statsd/src/condition/ConditionWizard.h
+++ b/cmds/statsd/src/condition/ConditionWizard.h
@@ -24,7 +24,7 @@
namespace os {
namespace statsd {
-// Held by MetricProducer, to query a condition state with input defined in EventConditionLink.
+// Held by MetricProducer, to query a condition state with input defined in MetricConditionLink.
class ConditionWizard : public virtual android::RefBase {
public:
ConditionWizard(){}; // for testing
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index 50cd130..18b93ee 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -34,16 +34,16 @@
SimpleConditionTracker::SimpleConditionTracker(
const ConfigKey& key, const string& name, const int index,
- const SimpleCondition& simpleCondition,
+ const SimplePredicate& simplePredicate,
const unordered_map<string, int>& trackerNameIndexMap)
: ConditionTracker(name, index), mConfigKey(key) {
VLOG("creating SimpleConditionTracker %s", mName.c_str());
- mCountNesting = simpleCondition.count_nesting();
+ mCountNesting = simplePredicate.count_nesting();
- if (simpleCondition.has_start()) {
- auto pair = trackerNameIndexMap.find(simpleCondition.start());
+ if (simplePredicate.has_start()) {
+ auto pair = trackerNameIndexMap.find(simplePredicate.start());
if (pair == trackerNameIndexMap.end()) {
- ALOGW("Start matcher %s not found in the config", simpleCondition.start().c_str());
+ ALOGW("Start matcher %s not found in the config", simplePredicate.start().c_str());
return;
}
mStartLogMatcherIndex = pair->second;
@@ -52,10 +52,10 @@
mStartLogMatcherIndex = -1;
}
- if (simpleCondition.has_stop()) {
- auto pair = trackerNameIndexMap.find(simpleCondition.stop());
+ if (simplePredicate.has_stop()) {
+ auto pair = trackerNameIndexMap.find(simplePredicate.stop());
if (pair == trackerNameIndexMap.end()) {
- ALOGW("Stop matcher %s not found in the config", simpleCondition.stop().c_str());
+ ALOGW("Stop matcher %s not found in the config", simplePredicate.stop().c_str());
return;
}
mStopLogMatcherIndex = pair->second;
@@ -64,10 +64,10 @@
mStopLogMatcherIndex = -1;
}
- if (simpleCondition.has_stop_all()) {
- auto pair = trackerNameIndexMap.find(simpleCondition.stop_all());
+ if (simplePredicate.has_stop_all()) {
+ auto pair = trackerNameIndexMap.find(simplePredicate.stop_all());
if (pair == trackerNameIndexMap.end()) {
- ALOGW("Stop all matcher %s not found in the config", simpleCondition.stop().c_str());
+ ALOGW("Stop all matcher %s not found in the config", simplePredicate.stop().c_str());
return;
}
mStopAllLogMatcherIndex = pair->second;
@@ -76,14 +76,14 @@
mStopAllLogMatcherIndex = -1;
}
- mOutputDimension.insert(mOutputDimension.begin(), simpleCondition.dimension().begin(),
- simpleCondition.dimension().end());
+ mOutputDimension.insert(mOutputDimension.begin(), simplePredicate.dimension().begin(),
+ simplePredicate.dimension().end());
if (mOutputDimension.size() > 0) {
mSliced = true;
}
- if (simpleCondition.initial_value() == SimpleCondition_InitialValue_FALSE) {
+ if (simplePredicate.initial_value() == SimplePredicate_InitialValue_FALSE) {
mInitialValue = ConditionState::kFalse;
} else {
mInitialValue = ConditionState::kUnknown;
@@ -98,7 +98,7 @@
VLOG("~SimpleConditionTracker()");
}
-bool SimpleConditionTracker::init(const vector<Condition>& allConditionConfig,
+bool SimpleConditionTracker::init(const vector<Predicate>& allConditionConfig,
const vector<sp<ConditionTracker>>& allConditionTrackers,
const unordered_map<string, int>& conditionNameIndexMap,
vector<bool>& stack) {
@@ -139,7 +139,7 @@
StatsdStats::getInstance().noteConditionDimensionSize(mConfigKey, mName, newTupleCount);
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
- ALOGE("Condition %s dropping data for dimension key %s", mName.c_str(), newKey.c_str());
+ ALOGE("Predicate %s dropping data for dimension key %s", mName.c_str(), newKey.c_str());
return true;
}
}
@@ -221,7 +221,7 @@
conditionChangedCache[mIndex] = changed;
conditionCache[mIndex] = newCondition;
- VLOG("SimpleCondition %s nonSlicedChange? %d", mName.c_str(),
+ VLOG("SimplePredicate %s nonSlicedChange? %d", mName.c_str(),
conditionChangedCache[mIndex] == true);
}
@@ -292,13 +292,13 @@
(pair == conditionParameters.end()) ? DEFAULT_DIMENSION_KEY : pair->second;
if (pair == conditionParameters.end() && mOutputDimension.size() > 0) {
- ALOGE("Condition %s output has dimension, but it's not specified in the query!",
+ ALOGE("Predicate %s output has dimension, but it's not specified in the query!",
mName.c_str());
conditionCache[mIndex] = mInitialValue;
return;
}
- VLOG("simpleCondition %s query key: %s", mName.c_str(), key.c_str());
+ VLOG("simplePredicate %s query key: %s", mName.c_str(), key.c_str());
auto startedCountIt = mSlicedConditionState.find(key);
if (startedCountIt == mSlicedConditionState.end()) {
@@ -308,7 +308,7 @@
startedCountIt->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
}
- VLOG("Condition %s return %d", mName.c_str(), conditionCache[mIndex]);
+ VLOG("Predicate %s return %d", mName.c_str(), conditionCache[mIndex]);
}
} // namespace statsd
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
index d21afd1..644d84c 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -30,12 +30,12 @@
class SimpleConditionTracker : public virtual ConditionTracker {
public:
SimpleConditionTracker(const ConfigKey& key, const std::string& name, const int index,
- const SimpleCondition& simpleCondition,
+ const SimplePredicate& simplePredicate,
const std::unordered_map<std::string, int>& trackerNameIndexMap);
~SimpleConditionTracker();
- bool init(const std::vector<Condition>& allConditionConfig,
+ bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
const std::unordered_map<std::string, int>& conditionNameIndexMap,
std::vector<bool>& stack) override;
diff --git a/cmds/statsd/src/condition/condition_util.cpp b/cmds/statsd/src/condition/condition_util.cpp
index 669a4b7..ff0e3bc 100644
--- a/cmds/statsd/src/condition/condition_util.cpp
+++ b/cmds/statsd/src/condition/condition_util.cpp
@@ -94,17 +94,17 @@
}
HashableDimensionKey getDimensionKeyForCondition(const LogEvent& event,
- const EventConditionLink& link) {
+ const MetricConditionLink& link) {
vector<KeyMatcher> eventKey;
- eventKey.reserve(link.key_in_main().size());
+ eventKey.reserve(link.key_in_what().size());
- for (const auto& key : link.key_in_main()) {
+ for (const auto& key : link.key_in_what()) {
eventKey.push_back(key);
}
vector<KeyValuePair> dimensionKey = getDimensionKey(event, eventKey);
- for (int i = 0; i < link.key_in_main_size(); i++) {
+ for (int i = 0; i < link.key_in_what_size(); i++) {
auto& kv = dimensionKey[i];
kv.set_key(link.key_in_condition(i).key());
}
diff --git a/cmds/statsd/src/condition/condition_util.h b/cmds/statsd/src/condition/condition_util.h
index 4167bf9..934c207 100644
--- a/cmds/statsd/src/condition/condition_util.h
+++ b/cmds/statsd/src/condition/condition_util.h
@@ -37,7 +37,7 @@
const std::vector<ConditionState>& conditionCache);
HashableDimensionKey getDimensionKeyForCondition(const LogEvent& event,
- const EventConditionLink& link);
+ const MetricConditionLink& link);
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index ac2192c..540199d 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -102,8 +102,8 @@
// Remove from map
if (it->first.GetUid() == uid) {
removed.push_back(it->first);
- it = mConfigs.erase(it);
mConfigReceivers.erase(it->first);
+ it = mConfigs.erase(it);
} else {
it++;
}
@@ -118,6 +118,28 @@
}
}
+void ConfigManager::RemoveAllConfigs() {
+ vector<ConfigKey> removed;
+
+ for (auto it = mConfigs.begin(); it != mConfigs.end();) {
+ // Remove from map
+ removed.push_back(it->first);
+ auto receiverIt = mConfigReceivers.find(it->first);
+ if (receiverIt != mConfigReceivers.end()) {
+ mConfigReceivers.erase(it->first);
+ }
+ it = mConfigs.erase(it);
+ }
+
+ // Remove separately so if they do anything in the callback they can't mess up our iteration.
+ for (auto& key : removed) {
+ // Tell everyone
+ for (auto& listener : mListeners) {
+ listener->OnConfigRemoved(key);
+ }
+ }
+}
+
vector<ConfigKey> ConfigManager::GetAllConfigKeys() const {
vector<ConfigKey> ret;
for (auto it = mConfigs.cbegin(); it != mConfigs.cend(); ++it) {
@@ -192,7 +214,8 @@
int UID_PROCESS_STATE_UID_KEY = 1;
int KERNEL_WAKELOCK_TAG_ID = 1004;
- int KERNEL_WAKELOCK_NAME_KEY = 4;
+ int KERNEL_WAKELOCK_COUNT_KEY = 2;
+ int KERNEL_WAKELOCK_NAME_KEY = 1;
int DEVICE_TEMPERATURE_TAG_ID = 33;
int DEVICE_TEMPERATURE_KEY = 1;
@@ -210,6 +233,9 @@
alert->set_number_of_buckets(6);
alert->set_trigger_if_sum_gt(10);
alert->set_refractory_period_secs(30);
+ Alert::IncidentdDetails* details = alert->mutable_incidentd_details();
+ details->add_section(12);
+ details->add_section(13);
// Count process state changes, slice by uid.
metric = config.add_count_metric();
@@ -226,6 +252,9 @@
alert->set_number_of_buckets(4);
alert->set_trigger_if_sum_gt(30);
alert->set_refractory_period_secs(20);
+ details = alert->mutable_incidentd_details();
+ details->add_section(14);
+ details->add_section(15);
// Count process state changes, slice by uid, while SCREEN_IS_OFF
metric = config.add_count_metric();
@@ -244,9 +273,9 @@
keyMatcher = metric->add_dimension();
keyMatcher->set_key(WAKE_LOCK_UID_KEY_ID);
metric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
- EventConditionLink* link = metric->add_links();
+ MetricConditionLink* link = metric->add_links();
link->set_condition("APP_IS_BACKGROUND");
- link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID);
+ link->add_key_in_what()->set_key(WAKE_LOCK_UID_KEY_ID);
link->add_key_in_condition()->set_key(APP_USAGE_UID_KEY_ID);
// Duration of an app holding any wl, while screen on and app in background, slice by uid
@@ -260,7 +289,7 @@
durationMetric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
link = durationMetric->add_links();
link->set_condition("APP_IS_BACKGROUND");
- link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID);
+ link->add_key_in_what()->set_key(WAKE_LOCK_UID_KEY_ID);
link->add_key_in_condition()->set_key(APP_USAGE_UID_KEY_ID);
// max Duration of an app holding any wl, while screen on and app in background, slice by uid
@@ -274,7 +303,7 @@
durationMetric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
link = durationMetric->add_links();
link->set_condition("APP_IS_BACKGROUND");
- link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID);
+ link->add_key_in_what()->set_key(WAKE_LOCK_UID_KEY_ID);
link->add_key_in_condition()->set_key(APP_USAGE_UID_KEY_ID);
// Duration of an app holding any wl, while screen on and app in background
@@ -286,7 +315,7 @@
durationMetric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
link = durationMetric->add_links();
link->set_condition("APP_IS_BACKGROUND");
- link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID);
+ link->add_key_in_what()->set_key(WAKE_LOCK_UID_KEY_ID);
link->add_key_in_condition()->set_key(APP_USAGE_UID_KEY_ID);
// Duration of screen on time.
@@ -296,11 +325,21 @@
durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
durationMetric->set_what("SCREEN_IS_ON");
+ // Anomaly threshold for background count.
+ alert = config.add_alert();
+ alert->set_name("ALERT_8");
+ alert->set_metric_name("METRIC_8");
+ alert->set_number_of_buckets(4);
+ alert->set_trigger_if_sum_gt(2000000000); // 2 seconds
+ alert->set_refractory_period_secs(120);
+ details = alert->mutable_incidentd_details();
+ details->add_section(-1);
+
// Value metric to count KERNEL_WAKELOCK when screen turned on
ValueMetric* valueMetric = config.add_value_metric();
valueMetric->set_name("METRIC_6");
valueMetric->set_what("KERNEL_WAKELOCK");
- valueMetric->set_value_field(1);
+ valueMetric->set_value_field(KERNEL_WAKELOCK_COUNT_KEY);
valueMetric->set_condition("SCREEN_IS_ON");
keyMatcher = valueMetric->add_dimension();
keyMatcher->set_key(KERNEL_WAKELOCK_NAME_KEY);
@@ -320,121 +359,121 @@
gaugeMetric->mutable_bucket()->set_bucket_size_millis(60 * 1000L);
// Event matchers............
- LogEntryMatcher* temperatureEntryMatcher = config.add_log_entry_matcher();
- temperatureEntryMatcher->set_name("DEVICE_TEMPERATURE");
- temperatureEntryMatcher->mutable_simple_log_entry_matcher()->set_tag(
+ AtomMatcher* temperatureAtomMatcher = config.add_atom_matcher();
+ temperatureAtomMatcher->set_name("DEVICE_TEMPERATURE");
+ temperatureAtomMatcher->mutable_simple_atom_matcher()->set_tag(
DEVICE_TEMPERATURE_TAG_ID);
- LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+ AtomMatcher* eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("SCREEN_TURNED_ON");
- SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->set_tag(SCREEN_EVENT_TAG_ID);
- KeyValueMatcher* keyValueMatcher = simpleLogEntryMatcher->add_key_value_matcher();
+ SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_tag(SCREEN_EVENT_TAG_ID);
+ KeyValueMatcher* keyValueMatcher = simpleAtomMatcher->add_key_value_matcher();
keyValueMatcher->mutable_key_matcher()->set_key(SCREEN_EVENT_STATE_KEY);
keyValueMatcher->set_eq_int(SCREEN_EVENT_ON_VALUE);
- eventMatcher = config.add_log_entry_matcher();
+ eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("SCREEN_TURNED_OFF");
- simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->set_tag(SCREEN_EVENT_TAG_ID);
- keyValueMatcher = simpleLogEntryMatcher->add_key_value_matcher();
+ simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_tag(SCREEN_EVENT_TAG_ID);
+ keyValueMatcher = simpleAtomMatcher->add_key_value_matcher();
keyValueMatcher->mutable_key_matcher()->set_key(SCREEN_EVENT_STATE_KEY);
keyValueMatcher->set_eq_int(SCREEN_EVENT_OFF_VALUE);
- eventMatcher = config.add_log_entry_matcher();
+ eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("PROCESS_STATE_CHANGE");
- simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->set_tag(UID_PROCESS_STATE_TAG_ID);
+ simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_tag(UID_PROCESS_STATE_TAG_ID);
- eventMatcher = config.add_log_entry_matcher();
+ eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("APP_GOES_BACKGROUND");
- simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->set_tag(APP_USAGE_ID);
- keyValueMatcher = simpleLogEntryMatcher->add_key_value_matcher();
+ simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_tag(APP_USAGE_ID);
+ keyValueMatcher = simpleAtomMatcher->add_key_value_matcher();
keyValueMatcher->mutable_key_matcher()->set_key(APP_USAGE_STATE_KEY);
keyValueMatcher->set_eq_int(APP_USAGE_BACKGROUND);
- eventMatcher = config.add_log_entry_matcher();
+ eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("APP_GOES_FOREGROUND");
- simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->set_tag(APP_USAGE_ID);
- keyValueMatcher = simpleLogEntryMatcher->add_key_value_matcher();
+ simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_tag(APP_USAGE_ID);
+ keyValueMatcher = simpleAtomMatcher->add_key_value_matcher();
keyValueMatcher->mutable_key_matcher()->set_key(APP_USAGE_STATE_KEY);
keyValueMatcher->set_eq_int(APP_USAGE_FOREGROUND);
- eventMatcher = config.add_log_entry_matcher();
+ eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("APP_GET_WL");
- simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->set_tag(WAKE_LOCK_TAG_ID);
- keyValueMatcher = simpleLogEntryMatcher->add_key_value_matcher();
+ simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_tag(WAKE_LOCK_TAG_ID);
+ keyValueMatcher = simpleAtomMatcher->add_key_value_matcher();
keyValueMatcher->mutable_key_matcher()->set_key(WAKE_LOCK_STATE_KEY);
keyValueMatcher->set_eq_int(WAKE_LOCK_ACQUIRE_VALUE);
- eventMatcher = config.add_log_entry_matcher();
+ eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("APP_RELEASE_WL");
- simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->set_tag(WAKE_LOCK_TAG_ID);
- keyValueMatcher = simpleLogEntryMatcher->add_key_value_matcher();
+ simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_tag(WAKE_LOCK_TAG_ID);
+ keyValueMatcher = simpleAtomMatcher->add_key_value_matcher();
keyValueMatcher->mutable_key_matcher()->set_key(WAKE_LOCK_STATE_KEY);
keyValueMatcher->set_eq_int(WAKE_LOCK_RELEASE_VALUE);
// pulled events
- eventMatcher = config.add_log_entry_matcher();
+ eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("KERNEL_WAKELOCK");
- simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->set_tag(KERNEL_WAKELOCK_TAG_ID);
+ simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_tag(KERNEL_WAKELOCK_TAG_ID);
- // Conditions.............
- Condition* condition = config.add_condition();
- condition->set_name("SCREEN_IS_ON");
- SimpleCondition* simpleCondition = condition->mutable_simple_condition();
- simpleCondition->set_start("SCREEN_TURNED_ON");
- simpleCondition->set_stop("SCREEN_TURNED_OFF");
- simpleCondition->set_count_nesting(false);
+ // Predicates.............
+ Predicate* predicate = config.add_predicate();
+ predicate->set_name("SCREEN_IS_ON");
+ SimplePredicate* simplePredicate = predicate->mutable_simple_predicate();
+ simplePredicate->set_start("SCREEN_TURNED_ON");
+ simplePredicate->set_stop("SCREEN_TURNED_OFF");
+ simplePredicate->set_count_nesting(false);
- condition = config.add_condition();
- condition->set_name("SCREEN_IS_OFF");
- simpleCondition = condition->mutable_simple_condition();
- simpleCondition->set_start("SCREEN_TURNED_OFF");
- simpleCondition->set_stop("SCREEN_TURNED_ON");
- simpleCondition->set_count_nesting(false);
+ predicate = config.add_predicate();
+ predicate->set_name("SCREEN_IS_OFF");
+ simplePredicate = predicate->mutable_simple_predicate();
+ simplePredicate->set_start("SCREEN_TURNED_OFF");
+ simplePredicate->set_stop("SCREEN_TURNED_ON");
+ simplePredicate->set_count_nesting(false);
- condition = config.add_condition();
- condition->set_name("APP_IS_BACKGROUND");
- simpleCondition = condition->mutable_simple_condition();
- simpleCondition->set_start("APP_GOES_BACKGROUND");
- simpleCondition->set_stop("APP_GOES_FOREGROUND");
- KeyMatcher* condition_dimension1 = simpleCondition->add_dimension();
- condition_dimension1->set_key(APP_USAGE_UID_KEY_ID);
- simpleCondition->set_count_nesting(false);
+ predicate = config.add_predicate();
+ predicate->set_name("APP_IS_BACKGROUND");
+ simplePredicate = predicate->mutable_simple_predicate();
+ simplePredicate->set_start("APP_GOES_BACKGROUND");
+ simplePredicate->set_stop("APP_GOES_FOREGROUND");
+ KeyMatcher* predicate_dimension1 = simplePredicate->add_dimension();
+ predicate_dimension1->set_key(APP_USAGE_UID_KEY_ID);
+ simplePredicate->set_count_nesting(false);
- condition = config.add_condition();
- condition->set_name("APP_IS_BACKGROUND_AND_SCREEN_ON");
- Condition_Combination* combination_condition = condition->mutable_combination();
- combination_condition->set_operation(LogicalOperation::AND);
- combination_condition->add_condition("APP_IS_BACKGROUND");
- combination_condition->add_condition("SCREEN_IS_ON");
+ predicate = config.add_predicate();
+ predicate->set_name("APP_IS_BACKGROUND_AND_SCREEN_ON");
+ Predicate_Combination* combination_predicate = predicate->mutable_combination();
+ combination_predicate->set_operation(LogicalOperation::AND);
+ combination_predicate->add_predicate("APP_IS_BACKGROUND");
+ combination_predicate->add_predicate("SCREEN_IS_ON");
- condition = config.add_condition();
- condition->set_name("WL_HELD_PER_APP_PER_NAME");
- simpleCondition = condition->mutable_simple_condition();
- simpleCondition->set_start("APP_GET_WL");
- simpleCondition->set_stop("APP_RELEASE_WL");
- KeyMatcher* condition_dimension = simpleCondition->add_dimension();
- condition_dimension->set_key(WAKE_LOCK_UID_KEY_ID);
- condition_dimension = simpleCondition->add_dimension();
- condition_dimension->set_key(WAKE_LOCK_NAME_KEY);
- simpleCondition->set_count_nesting(true);
+ predicate = config.add_predicate();
+ predicate->set_name("WL_HELD_PER_APP_PER_NAME");
+ simplePredicate = predicate->mutable_simple_predicate();
+ simplePredicate->set_start("APP_GET_WL");
+ simplePredicate->set_stop("APP_RELEASE_WL");
+ KeyMatcher* predicate_dimension = simplePredicate->add_dimension();
+ predicate_dimension->set_key(WAKE_LOCK_UID_KEY_ID);
+ predicate_dimension = simplePredicate->add_dimension();
+ predicate_dimension->set_key(WAKE_LOCK_NAME_KEY);
+ simplePredicate->set_count_nesting(true);
- condition = config.add_condition();
- condition->set_name("WL_HELD_PER_APP");
- simpleCondition = condition->mutable_simple_condition();
- simpleCondition->set_start("APP_GET_WL");
- simpleCondition->set_stop("APP_RELEASE_WL");
- simpleCondition->set_initial_value(SimpleCondition_InitialValue_FALSE);
- condition_dimension = simpleCondition->add_dimension();
- condition_dimension->set_key(WAKE_LOCK_UID_KEY_ID);
- simpleCondition->set_count_nesting(true);
+ predicate = config.add_predicate();
+ predicate->set_name("WL_HELD_PER_APP");
+ simplePredicate = predicate->mutable_simple_predicate();
+ simplePredicate->set_start("APP_GET_WL");
+ simplePredicate->set_stop("APP_RELEASE_WL");
+ simplePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE);
+ predicate_dimension = simplePredicate->add_dimension();
+ predicate_dimension->set_key(WAKE_LOCK_UID_KEY_ID);
+ simplePredicate->set_count_nesting(true);
return config;
}
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index 578e5ac..90ea6c0 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -98,6 +98,11 @@
void RemoveConfigs(int uid);
/**
+ * Remove all of the configs from memory.
+ */
+ void RemoveAllConfigs();
+
+ /**
* Text dump of our state for debugging.
*/
void Dump(FILE* out);
diff --git a/cmds/statsd/src/external/StatsCompanionServicePuller.cpp b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
index 8e96399..ffe1be9 100644
--- a/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
+++ b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
@@ -45,20 +45,22 @@
if (statsCompanion != NULL) {
Status status = statsCompanion->pullData(tagId, &returned_value);
if (!status.isOk()) {
- ALOGW("error pulling kernel wakelock");
+ ALOGW("error pulling for %d", tagId);
return false;
}
data->clear();
+ int timestamp = time(nullptr);
for (const StatsLogEventWrapper& it : returned_value) {
log_msg tmp;
tmp.entry_v1.len = it.bytes.size();
// Manually set the header size to 28 bytes to match the pushed log events.
tmp.entry.hdr_size = kLogMsgHeaderSize;
+ tmp.entry_v1.sec = timestamp;
// And set the received bytes starting after the 28 bytes reserved for header.
std::copy(it.bytes.begin(), it.bytes.end(), tmp.buf + kLogMsgHeaderSize);
data->push_back(make_shared<LogEvent>(tmp));
}
- ALOGD("KernelWakelockPuller::pull succeeded!");
+ ALOGD("StatsCompanionServicePuller::pull succeeded for %d", tagId);
return true;
} else {
ALOGW("statsCompanion not found!");
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
index 3ffcd77..c4688a2 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
@@ -76,7 +76,9 @@
if (DEBUG) ALOGD("Initiating pulling %d", tagId);
if (mPullers.find(tagId) != mPullers.end()) {
- return mPullers.find(tagId)->second->Pull(tagId, data);
+ bool ret = mPullers.find(tagId)->second->Pull(tagId, data);
+ ALOGD("pulled %d items", (int)data->size());
+ return ret;
} else {
ALOGD("Unknown tagId %d", tagId);
return false; // Return early since we don't know what to pull.
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 815e03f..b02b9da 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -41,10 +41,9 @@
const int FIELD_ID_BEGIN_TIME = 1;
const int FIELD_ID_END_TIME = 2;
const int FIELD_ID_CONFIG_STATS = 3;
-const int FIELD_ID_MATCHER_STATS = 4;
-const int FIELD_ID_CONDITION_STATS = 5;
-const int FIELD_ID_METRIC_STATS = 6;
const int FIELD_ID_ATOM_STATS = 7;
+const int FIELD_ID_UIDMAP_STATS = 8;
+const int FIELD_ID_ANOMALY_ALARM_STATS = 9;
const int FIELD_ID_MATCHER_STATS_NAME = 1;
const int FIELD_ID_MATCHER_STATS_COUNT = 2;
@@ -58,10 +57,12 @@
const int FIELD_ID_ATOM_STATS_TAG = 1;
const int FIELD_ID_ATOM_STATS_COUNT = 2;
+const int FIELD_ID_ANOMALY_ALARMS_REGISTERED = 1;
+
// TODO: add stats for pulled atoms.
StatsdStats::StatsdStats() {
mPushedAtomStats.resize(android::util::kMaxPushedAtomId + 1);
- mStartTime = time(nullptr);
+ mStartTimeSec = time(nullptr);
}
StatsdStats& StatsdStats::getInstance() {
@@ -100,13 +101,15 @@
if (it != mConfigStats.end()) {
int32_t nowTimeSec = time(nullptr);
it->second.set_deletion_time_sec(nowTimeSec);
- // Add condition stats, metrics stats, matcher stats
- addSubStatsToConfig(key, it->second);
+ // Add condition stats, metrics stats, matcher stats, alert stats
+ addSubStatsToConfigLocked(key, it->second);
// Remove them after they are added to the config stats.
mMatcherStats.erase(key);
mMetricsStats.erase(key);
+ mAlertStats.erase(key);
mConditionStats.erase(key);
mIceBox.push_back(it->second);
+ mConfigStats.erase(it);
}
}
@@ -116,25 +119,81 @@
}
void StatsdStats::noteBroadcastSent(const ConfigKey& key) {
- lock_guard<std::mutex> lock(mLock);
- auto it = mConfigStats.find(key);
- if (it == mConfigStats.end()) {
- ALOGE("Config key %s not found!", key.ToString().c_str());
- return;
- }
-
- it->second.add_broadcast_sent_time_sec(time(nullptr));
+ noteBroadcastSent(key, time(nullptr));
}
-void StatsdStats::noteDataDrop(const ConfigKey& key) {
+void StatsdStats::noteBroadcastSent(const ConfigKey& key, int32_t timeSec) {
lock_guard<std::mutex> lock(mLock);
auto it = mConfigStats.find(key);
if (it == mConfigStats.end()) {
ALOGE("Config key %s not found!", key.ToString().c_str());
return;
}
+ if (it->second.broadcast_sent_time_sec_size() >= kMaxTimestampCount) {
+ auto timestampList = it->second.mutable_broadcast_sent_time_sec();
+ // This is O(N) operation. It shouldn't happen often, and N is only 20.
+ timestampList->erase(timestampList->begin());
+ }
+ it->second.add_broadcast_sent_time_sec(timeSec);
+}
- it->second.add_data_drop_time_sec(time(nullptr));
+void StatsdStats::noteDataDropped(const ConfigKey& key) {
+ noteDataDropped(key, time(nullptr));
+}
+
+void StatsdStats::noteDataDropped(const ConfigKey& key, int32_t timeSec) {
+ lock_guard<std::mutex> lock(mLock);
+ auto it = mConfigStats.find(key);
+ if (it == mConfigStats.end()) {
+ ALOGE("Config key %s not found!", key.ToString().c_str());
+ return;
+ }
+ if (it->second.data_drop_time_sec_size() >= kMaxTimestampCount) {
+ auto timestampList = it->second.mutable_data_drop_time_sec();
+ // This is O(N) operation. It shouldn't happen often, and N is only 20.
+ timestampList->erase(timestampList->begin());
+ }
+ it->second.add_data_drop_time_sec(timeSec);
+}
+
+void StatsdStats::noteMetricsReportSent(const ConfigKey& key) {
+ noteMetricsReportSent(key, time(nullptr));
+}
+
+void StatsdStats::noteMetricsReportSent(const ConfigKey& key, int32_t timeSec) {
+ lock_guard<std::mutex> lock(mLock);
+ auto it = mConfigStats.find(key);
+ if (it == mConfigStats.end()) {
+ ALOGE("Config key %s not found!", key.ToString().c_str());
+ return;
+ }
+ if (it->second.dump_report_time_sec_size() >= kMaxTimestampCount) {
+ auto timestampList = it->second.mutable_dump_report_time_sec();
+ // This is O(N) operation. It shouldn't happen often, and N is only 20.
+ timestampList->erase(timestampList->begin());
+ }
+ it->second.add_dump_report_time_sec(timeSec);
+}
+
+void StatsdStats::noteUidMapDropped(int snapshots, int deltas) {
+ lock_guard<std::mutex> lock(mLock);
+ mUidMapStats.set_dropped_snapshots(mUidMapStats.dropped_snapshots() + snapshots);
+ mUidMapStats.set_dropped_changes(mUidMapStats.dropped_changes() + deltas);
+}
+
+void StatsdStats::setUidMapSnapshots(int snapshots) {
+ lock_guard<std::mutex> lock(mLock);
+ mUidMapStats.set_snapshots(snapshots);
+}
+
+void StatsdStats::setUidMapChanges(int changes) {
+ lock_guard<std::mutex> lock(mLock);
+ mUidMapStats.set_changes(changes);
+}
+
+void StatsdStats::setCurrentUidMapMemory(int bytes) {
+ lock_guard<std::mutex> lock(mLock);
+ mUidMapStats.set_bytes_used(bytes);
}
void StatsdStats::noteConditionDimensionSize(const ConfigKey& key, const string& name, int size) {
@@ -161,10 +220,21 @@
matcherStats[name]++;
}
+void StatsdStats::noteAnomalyDeclared(const ConfigKey& key, const string& name) {
+ lock_guard<std::mutex> lock(mLock);
+ auto& alertStats = mAlertStats[key];
+ alertStats[name]++;
+}
+
+void StatsdStats::noteRegisteredAnomalyAlarmChanged() {
+ lock_guard<std::mutex> lock(mLock);
+ mAnomalyAlarmRegisteredStats++;
+}
+
void StatsdStats::noteAtomLogged(int atomId, int32_t timeSec) {
lock_guard<std::mutex> lock(mLock);
- if (timeSec < mStartTime) {
+ if (timeSec < mStartTimeSec) {
return;
}
@@ -183,15 +253,26 @@
void StatsdStats::resetInternalLocked() {
// Reset the historical data, but keep the active ConfigStats
- mStartTime = time(nullptr);
+ mStartTimeSec = time(nullptr);
mIceBox.clear();
mConditionStats.clear();
mMetricsStats.clear();
std::fill(mPushedAtomStats.begin(), mPushedAtomStats.end(), 0);
+ mAlertStats.clear();
+ mAnomalyAlarmRegisteredStats = 0;
mMatcherStats.clear();
+ for (auto& config : mConfigStats) {
+ config.second.clear_broadcast_sent_time_sec();
+ config.second.clear_data_drop_time_sec();
+ config.second.clear_dump_report_time_sec();
+ config.second.clear_matcher_stats();
+ config.second.clear_condition_stats();
+ config.second.clear_metric_stats();
+ config.second.clear_alert_stats();
+ }
}
-void StatsdStats::addSubStatsToConfig(const ConfigKey& key,
+void StatsdStats::addSubStatsToConfigLocked(const ConfigKey& key,
StatsdStatsReport_ConfigStats& configStats) {
// Add matcher stats
if (mMatcherStats.find(key) != mMatcherStats.end()) {
@@ -223,13 +304,23 @@
VLOG("metrics %s max output tuple size %d", stats.first.c_str(), stats.second);
}
}
+ // Add anomaly detection alert stats
+ if (mAlertStats.find(key) != mAlertStats.end()) {
+ const auto& alertStats = mAlertStats[key];
+ for (const auto& stats : alertStats) {
+ auto output = configStats.add_alert_stats();
+ output->set_name(stats.first);
+ output->set_declared_times(stats.second);
+ VLOG("alert %s declared %d times", stats.first.c_str(), stats.second);
+ }
+ }
}
-void StatsdStats::dumpStats(std::vector<int8_t>* output, bool reset) {
+void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) {
lock_guard<std::mutex> lock(mLock);
if (DEBUG) {
- time_t t = time(nullptr);
+ time_t t = mStartTimeSec;
struct tm* tm = localtime(&t);
char timeBuffer[80];
strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %I:%M%p", tm);
@@ -237,7 +328,7 @@
VLOG("Stats collection start second: %s", timeBuffer);
}
ProtoOutputStream proto;
- proto.write(FIELD_TYPE_INT32 | FIELD_ID_BEGIN_TIME, mStartTime);
+ proto.write(FIELD_TYPE_INT32 | FIELD_ID_BEGIN_TIME, mStartTimeSec);
proto.write(FIELD_TYPE_INT32 | FIELD_ID_END_TIME, (int32_t)time(nullptr));
VLOG("%lu Config in icebox: ", (unsigned long)mIceBox.size());
@@ -286,9 +377,13 @@
for (const auto& dataDropTime : configStats.data_drop_time_sec()) {
VLOG("\tdata drop time: %d", dataDropTime);
}
+
+ for (const auto& dumpTime : configStats.dump_report_time_sec()) {
+ VLOG("\tdump report time: %d", dumpTime);
+ }
}
- addSubStatsToConfig(pair.first, configStats);
+ addSubStatsToConfigLocked(pair.first, configStats);
const int numBytes = configStats.ByteSize();
vector<char> buffer(numBytes);
@@ -300,6 +395,7 @@
configStats.clear_matcher_stats();
configStats.clear_condition_stats();
configStats.clear_metric_stats();
+ configStats.clear_alert_stats();
}
VLOG("********Atom stats***********");
@@ -316,6 +412,24 @@
}
}
+ if (mAnomalyAlarmRegisteredStats > 0) {
+ VLOG("********AnomalyAlarmStats stats***********");
+ long long token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_ANOMALY_ALARM_STATS);
+ proto.write(FIELD_TYPE_INT32 | FIELD_ID_ANOMALY_ALARMS_REGISTERED,
+ mAnomalyAlarmRegisteredStats);
+ proto.end(token);
+ VLOG("Anomaly alarm registrations: %d", mAnomalyAlarmRegisteredStats);
+ }
+
+ const int numBytes = mUidMapStats.ByteSize();
+ vector<char> buffer(numBytes);
+ mUidMapStats.SerializeToArray(&buffer[0], numBytes);
+ proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UIDMAP_STATS, &buffer[0], buffer.size());
+ VLOG("UID map stats: bytes=%d, snapshots=%d, changes=%d, snapshots lost=%d, changes "
+ "lost=%d",
+ mUidMapStats.bytes_used(), mUidMapStats.snapshots(), mUidMapStats.changes(),
+ mUidMapStats.dropped_snapshots(), mUidMapStats.dropped_changes());
+
output->clear();
size_t bufferSize = proto.size();
output->resize(bufferSize);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 73ce279..4cf168e 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -18,6 +18,8 @@
#include "config/ConfigKey.h"
#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include <gtest/gtest_prod.h>
+#include <log/log_time.h>
#include <mutex>
#include <string>
#include <vector>
@@ -42,6 +44,22 @@
const static int kMaxMetricCountPerConfig = 300;
const static int kMaxMatcherCountPerConfig = 500;
+ const static int kMaxTimestampCount = 20;
+
+ // Max memory allowed for storing metrics per configuration. When this limit is approached,
+ // statsd will send a broadcast so that the client can fetch the data and clear this memory.
+ static const size_t kMaxMetricsBytesPerConfig = 128 * 1024;
+
+ // Cap the UID map's memory usage to this. This should be fairly high since the UID information
+ // is critical for understanding the metrics.
+ const static size_t kMaxBytesUsedUidMap = 50 * 1024;
+
+ /* Minimum period between two broadcasts in nanoseconds. */
+ static const unsigned long long kMinBroadcastPeriodNs = 60 * NS_PER_SEC;
+
+ /* Min period between two checks of byte size per config key in nanoseconds. */
+ static const unsigned long long kMinByteSizeCheckPeriodNs = 10 * NS_PER_SEC;
+
/**
* Report a new config has been received and report the static stats about the config.
*
@@ -63,7 +81,14 @@
/**
* Report a config's metrics data has been dropped.
*/
- void noteDataDrop(const ConfigKey& key);
+ void noteDataDropped(const ConfigKey& key);
+
+ /**
+ * Report metrics data report has been sent.
+ *
+ * The report may be requested via StatsManager API, or through adb cmd.
+ */
+ void noteMetricsReportSent(const ConfigKey& key);
/**
* Report the size of output tuple of a condition.
@@ -98,11 +123,36 @@
void noteMatcherMatched(const ConfigKey& key, const std::string& name);
/**
+ * Report that an anomaly detection alert has been declared.
+ *
+ * [key]: The config key that this alert belongs to.
+ * [name]: The name of the alert.
+ */
+ void noteAnomalyDeclared(const ConfigKey& key, const std::string& name);
+
+ /**
* Report an atom event has been logged.
*/
void noteAtomLogged(int atomId, int32_t timeSec);
/**
+ * Report that statsd modified the anomaly alarm registered with StatsCompanionService.
+ */
+ void noteRegisteredAnomalyAlarmChanged();
+
+ /**
+ * Records the number of snapshot and delta entries that are being dropped from the uid map.
+ */
+ void noteUidMapDropped(int snapshots, int deltas);
+
+ /**
+ * Updates the number of snapshots currently stored in the uid map.
+ */
+ void setUidMapSnapshots(int snapshots);
+ void setUidMapChanges(int changes);
+ void setCurrentUidMapMemory(int bytes);
+
+ /**
* Reset the historical stats. Including all stats in icebox, and the tracked stats about
* metrics, matchers, and atoms. The active configs will be kept and StatsdStats will continue
* to collect stats after reset() has been called.
@@ -114,14 +164,17 @@
*
* [reset]: whether to clear the historical stats after the call.
*/
- void dumpStats(std::vector<int8_t>* buffer, bool reset);
+ void dumpStats(std::vector<uint8_t>* buffer, bool reset);
private:
StatsdStats();
mutable std::mutex mLock;
- int32_t mStartTime;
+ int32_t mStartTimeSec;
+
+ // Track the number of dropped entries used by the uid map.
+ StatsdStatsReport_UidMapStats mUidMapStats;
// The stats about the configs that are still in use.
std::map<const ConfigKey, StatsdStatsReport_ConfigStats> mConfigStats;
@@ -145,6 +198,14 @@
// This is a vector, not a map because it will be accessed A LOT -- for each stats log.
std::vector<int> mPushedAtomStats;
+ // Stores the number of times statsd modified the anomaly alarm registered with
+ // StatsCompanionService.
+ int mAnomalyAlarmRegisteredStats = 0;
+
+ // Stores the number of times an anomaly detection alert has been declared
+ // (per config, per alert name).
+ std::map<const ConfigKey, std::map<const std::string, int>> mAlertStats;
+
// Stores how many times a matcher have been matched.
std::map<const ConfigKey, std::map<const std::string, int>> mMatcherStats;
@@ -152,7 +213,22 @@
void resetInternalLocked();
- void addSubStatsToConfig(const ConfigKey& key, StatsdStatsReport_ConfigStats& configStats);
+ void addSubStatsToConfigLocked(const ConfigKey& key,
+ StatsdStatsReport_ConfigStats& configStats);
+
+ void noteDataDropped(const ConfigKey& key, int32_t timeSec);
+
+ void noteMetricsReportSent(const ConfigKey& key, int32_t timeSec);
+
+ void noteBroadcastSent(const ConfigKey& key, int32_t timeSec);
+
+ FRIEND_TEST(StatsdStatsTest, TestValidConfigAdd);
+ FRIEND_TEST(StatsdStatsTest, TestInvalidConfigAdd);
+ FRIEND_TEST(StatsdStatsTest, TestConfigRemove);
+ FRIEND_TEST(StatsdStatsTest, TestSubStats);
+ FRIEND_TEST(StatsdStatsTest, TestAtomLog);
+ FRIEND_TEST(StatsdStatsTest, TestTimestampThreshold);
+ FRIEND_TEST(StatsdStatsTest, TestAnomalyMonitor);
};
} // namespace statsd
diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
index 78ba762..51a38b6 100644
--- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
@@ -36,7 +36,7 @@
CombinationLogMatchingTracker::~CombinationLogMatchingTracker() {
}
-bool CombinationLogMatchingTracker::init(const vector<LogEntryMatcher>& allLogMatchers,
+bool CombinationLogMatchingTracker::init(const vector<AtomMatcher>& allLogMatchers,
const vector<sp<LogMatchingTracker>>& allTrackers,
const unordered_map<string, int>& matcherMap,
vector<bool>& stack) {
@@ -47,7 +47,7 @@
// mark this node as visited in the recursion stack.
stack[mIndex] = true;
- LogEntryMatcher_Combination matcher = allLogMatchers[mIndex].combination();
+ AtomMatcher_Combination matcher = allLogMatchers[mIndex].combination();
// LogicalOperation is missing in the config
if (!matcher.has_operation()) {
diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
index adb691e..81f6e80 100644
--- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
@@ -28,12 +28,12 @@
namespace os {
namespace statsd {
-// Represents a LogEntryMatcher_Combination in the StatsdConfig.
+// Represents a AtomMatcher_Combination in the StatsdConfig.
class CombinationLogMatchingTracker : public virtual LogMatchingTracker {
public:
CombinationLogMatchingTracker(const std::string& name, const int index);
- bool init(const std::vector<LogEntryMatcher>& allLogMatchers,
+ bool init(const std::vector<AtomMatcher>& allLogMatchers,
const std::vector<sp<LogMatchingTracker>>& allTrackers,
const std::unordered_map<std::string, int>& matcherMap,
std::vector<bool>& stack);
diff --git a/cmds/statsd/src/matchers/LogMatchingTracker.h b/cmds/statsd/src/matchers/LogMatchingTracker.h
index fea3e9b..8162c44 100644
--- a/cmds/statsd/src/matchers/LogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/LogMatchingTracker.h
@@ -39,14 +39,14 @@
virtual ~LogMatchingTracker(){};
// Initialize this LogMatchingTracker.
- // allLogMatchers: the list of the LogEntryMatcher proto config. This is needed because we don't
+ // allLogMatchers: the list of the AtomMatcher proto config. This is needed because we don't
// store the proto object in memory. We only need it during initilization.
// allTrackers: the list of the LogMatchingTracker objects. It's a one-to-one mapping with
// allLogMatchers. This is needed because the initialization is done recursively
// for CombinationLogMatchingTrackers using DFS.
// stack: a bit map to record which matcher has been visited on the stack. This is for detecting
// circle dependency.
- virtual bool init(const std::vector<LogEntryMatcher>& allLogMatchers,
+ virtual bool init(const std::vector<AtomMatcher>& allLogMatchers,
const std::vector<sp<LogMatchingTracker>>& allTrackers,
const std::unordered_map<std::string, int>& matcherMap,
std::vector<bool>& stack) = 0;
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
index ad37b01..ac217ab 100644
--- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
@@ -30,7 +30,7 @@
SimpleLogMatchingTracker::SimpleLogMatchingTracker(const string& name, const int index,
- const SimpleLogEntryMatcher& matcher)
+ const SimpleAtomMatcher& matcher)
: LogMatchingTracker(name, index), mMatcher(matcher) {
if (!matcher.has_tag()) {
mInitialized = false;
@@ -43,7 +43,7 @@
SimpleLogMatchingTracker::~SimpleLogMatchingTracker() {
}
-bool SimpleLogMatchingTracker::init(const vector<LogEntryMatcher>& allLogMatchers,
+bool SimpleLogMatchingTracker::init(const vector<AtomMatcher>& allLogMatchers,
const vector<sp<LogMatchingTracker>>& allTrackers,
const unordered_map<string, int>& matcherMap,
vector<bool>& stack) {
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
index 5dca55e..2c188c1 100644
--- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
@@ -32,11 +32,11 @@
class SimpleLogMatchingTracker : public virtual LogMatchingTracker {
public:
SimpleLogMatchingTracker(const std::string& name, const int index,
- const SimpleLogEntryMatcher& matcher);
+ const SimpleAtomMatcher& matcher);
~SimpleLogMatchingTracker();
- bool init(const std::vector<LogEntryMatcher>& allLogMatchers,
+ bool init(const std::vector<AtomMatcher>& allLogMatchers,
const std::vector<sp<LogMatchingTracker>>& allTrackers,
const std::unordered_map<std::string, int>& matcherMap,
std::vector<bool>& stack) override;
@@ -46,7 +46,7 @@
std::vector<MatchingState>& matcherResults) override;
private:
- const SimpleLogEntryMatcher mMatcher;
+ const SimpleAtomMatcher mMatcher;
};
} // namespace statsd
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index f7352cd..9e88e5d0 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -91,7 +91,7 @@
return matched;
}
-bool matchesSimple(const SimpleLogEntryMatcher& simpleMatcher, const LogEvent& event) {
+bool matchesSimple(const SimpleAtomMatcher& simpleMatcher, const LogEvent& event) {
const int tagId = event.GetTagId();
if (simpleMatcher.tag() != tagId) {
@@ -117,6 +117,9 @@
allMatched = false;
break;
}
+ } else {
+ allMatched = false;
+ break;
}
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kEqInt ||
matcherCase == KeyValueMatcher::ValueMatcherCase::kLtInt ||
@@ -153,6 +156,9 @@
break;
}
}
+ } else {
+ allMatched = false;
+ break;
}
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kEqBool) {
// Boolean fields
@@ -163,6 +169,9 @@
allMatched = false;
break;
}
+ } else {
+ allMatched = false;
+ break;
}
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kLtFloat ||
matcherCase == KeyValueMatcher::ValueMatcherCase::kGtFloat) {
@@ -181,6 +190,9 @@
break;
}
}
+ } else {
+ allMatched = false;
+ break;
}
} else {
// If value matcher is not present, assume that we match.
diff --git a/cmds/statsd/src/matchers/matcher_util.h b/cmds/statsd/src/matchers/matcher_util.h
index 4ea6f0b..f54ab36 100644
--- a/cmds/statsd/src/matchers/matcher_util.h
+++ b/cmds/statsd/src/matchers/matcher_util.h
@@ -42,7 +42,7 @@
bool combinationMatch(const std::vector<int>& children, const LogicalOperation& operation,
const std::vector<MatchingState>& matcherResults);
-bool matchesSimple(const SimpleLogEntryMatcher& simpleMatcher, const LogEvent& wrapper);
+bool matchesSimple(const SimpleAtomMatcher& simpleMatcher, const LogEvent& wrapper);
std::vector<KeyValuePair> getDimensionKey(const LogEvent& event,
const std::vector<KeyMatcher>& dimensions);
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index ce60eb9..36ec6b9 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -62,8 +62,6 @@
const int FIELD_ID_END_BUCKET_NANOS = 2;
const int FIELD_ID_COUNT = 3;
-// TODO: add back AnomalyTracker.
-
CountMetricProducer::CountMetricProducer(const ConfigKey& key, const CountMetric& metric,
const int conditionIndex,
const sp<ConditionWizard>& wizard,
@@ -85,7 +83,7 @@
mConditionSliced = true;
}
- startNewProtoOutputStream(mStartTimeNs);
+ startNewProtoOutputStreamLocked(mStartTimeNs);
VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
@@ -95,7 +93,7 @@
VLOG("~CountMetricProducer() called");
}
-void CountMetricProducer::startNewProtoOutputStream(long long startTime) {
+void CountMetricProducer::startNewProtoOutputStreamLocked(long long startTime) {
mProto = std::make_unique<ProtoOutputStream>();
mProto->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
@@ -105,17 +103,17 @@
void CountMetricProducer::finish() {
}
-void CountMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
+void CountMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
VLOG("Metric %s onSlicedConditionMayChange", mMetric.name().c_str());
}
-std::unique_ptr<std::vector<uint8_t>> CountMetricProducer::onDumpReport() {
+std::unique_ptr<std::vector<uint8_t>> CountMetricProducer::onDumpReportLocked() {
long long endTime = time(nullptr) * NS_PER_SEC;
// Dump current bucket if it's stale.
// If current bucket is still on-going, don't force dump current bucket.
// In finish(), We can force dump current bucket.
- flushIfNeeded(endTime);
+ flushIfNeededLocked(endTime);
VLOG("metric %s dump report now...", mMetric.name().c_str());
for (const auto& counter : mPastBuckets) {
@@ -167,9 +165,9 @@
(long long)mCurrentBucketStartTimeNs);
VLOG("metric %s dump report now...", mMetric.name().c_str());
- std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
+ std::unique_ptr<std::vector<uint8_t>> buffer = serializeProtoLocked();
- startNewProtoOutputStream(endTime);
+ startNewProtoOutputStreamLocked(endTime);
mPastBuckets.clear();
return buffer;
@@ -177,12 +175,13 @@
// TODO: Clear mDimensionKeyMap once the report is dumped.
}
-void CountMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
+void CountMetricProducer::onConditionChangedLocked(const bool conditionMet,
+ const uint64_t eventTime) {
VLOG("Metric %s onConditionChanged", mMetric.name().c_str());
mCondition = conditionMet;
}
-bool CountMetricProducer::hitGuardRail(const HashableDimensionKey& newKey) {
+bool CountMetricProducer::hitGuardRailLocked(const HashableDimensionKey& newKey) {
if (mCurrentSlicedCounter->find(newKey) != mCurrentSlicedCounter->end()) {
return false;
}
@@ -202,13 +201,14 @@
return false;
}
-void CountMetricProducer::onMatchedLogEventInternal(
+
+void CountMetricProducer::onMatchedLogEventInternalLocked(
const size_t matcherIndex, const HashableDimensionKey& eventKey,
const map<string, HashableDimensionKey>& conditionKey, bool condition,
const LogEvent& event, bool scheduledPull) {
uint64_t eventTimeNs = event.GetTimestampNs();
- flushIfNeeded(eventTimeNs);
+ flushIfNeededLocked(eventTimeNs);
if (condition == false) {
return;
@@ -218,7 +218,7 @@
if (it == mCurrentSlicedCounter->end()) {
// ===========GuardRail==============
- if (hitGuardRail(eventKey)) {
+ if (hitGuardRailLocked(eventKey)) {
return;
}
@@ -241,7 +241,7 @@
// When a new matched event comes in, we check if event falls into the current
// bucket. If not, flush the old counter to past buckets and initialize the new bucket.
-void CountMetricProducer::flushIfNeeded(const uint64_t eventTimeNs) {
+void CountMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
if (eventTimeNs < mCurrentBucketStartTimeNs + mBucketSizeNs) {
return;
}
@@ -274,7 +274,7 @@
// Rough estimate of CountMetricProducer buffer stored. This number will be
// greater than actual data size as it contains each dimension of
// CountMetricData is duplicated.
-size_t CountMetricProducer::byteSize() const {
+size_t CountMetricProducer::byteSizeLocked() const {
size_t totalSize = 0;
for (const auto& pair : mPastBuckets) {
totalSize += pair.second.size() * kBucketSize;
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index f78a199..800a2b9 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -48,33 +48,39 @@
virtual ~CountMetricProducer();
- void onConditionChanged(const bool conditionMet, const uint64_t eventTime) override;
-
void finish() override;
- void flushIfNeeded(const uint64_t newEventTime) override;
-
- // TODO: Pass a timestamp as a parameter in onDumpReport.
- std::unique_ptr<std::vector<uint8_t>> onDumpReport() override;
-
- void onSlicedConditionMayChange(const uint64_t eventTime) override;
-
- size_t byteSize() const override;
-
// TODO: Implement this later.
- virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
+ virtual void notifyAppUpgrade(const string& apk, const int uid, const int64_t version)
+ override{};
// TODO: Implement this later.
virtual void notifyAppRemoved(const string& apk, const int uid) override{};
protected:
- void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey,
- const std::map<std::string, HashableDimensionKey>& conditionKey,
- bool condition, const LogEvent& event,
- bool scheduledPull) override;
-
- void startNewProtoOutputStream(long long timestamp) override;
+ void onMatchedLogEventInternalLocked(
+ const size_t matcherIndex, const HashableDimensionKey& eventKey,
+ const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition,
+ const LogEvent& event, bool scheduledPull) override;
private:
+ // TODO: Pass a timestamp as a parameter in onDumpReport.
+ std::unique_ptr<std::vector<uint8_t>> onDumpReportLocked() override;
+
+ // Internal interface to handle condition change.
+ void onConditionChangedLocked(const bool conditionMet, const uint64_t eventTime) override;
+
+ // Internal interface to handle sliced condition change.
+ void onSlicedConditionMayChangeLocked(const uint64_t eventTime) override;
+
+ // Internal function to calculate the current used bytes.
+ size_t byteSizeLocked() const override;
+
+ // Util function to flush the old packet.
+ void flushIfNeededLocked(const uint64_t& newEventTime);
+
+ // Util function to init/reset the proto output stream.
+ void startNewProtoOutputStreamLocked(long long timestamp);
+
const CountMetric mMetric;
// TODO: Add a lock to mPastBuckets.
@@ -85,7 +91,7 @@
static const size_t kBucketSize = sizeof(CountBucket{});
- bool hitGuardRail(const HashableDimensionKey& newKey);
+ bool hitGuardRailLocked(const HashableDimensionKey& newKey);
FRIEND_TEST(CountMetricProducerTest, TestNonDimensionalEvents);
FRIEND_TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition);
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index a0374c0..cedea30 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -93,7 +93,7 @@
mConditionSliced = true;
}
- startNewProtoOutputStream(mStartTimeNs);
+ startNewProtoOutputStreamLocked(mStartTimeNs);
VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
@@ -103,7 +103,18 @@
VLOG("~DurationMetric() called");
}
-void DurationMetricProducer::startNewProtoOutputStream(long long startTime) {
+sp<AnomalyTracker> DurationMetricProducer::createAnomalyTracker(const Alert &alert) {
+ if (alert.trigger_if_sum_gt() > alert.number_of_buckets() * mBucketSizeNs) {
+ ALOGW("invalid alert: threshold (%lld) > possible recordable value (%d x %lld)",
+ alert.trigger_if_sum_gt(), alert.number_of_buckets(),
+ (long long)mBucketSizeNs);
+ return nullptr;
+ }
+ // TODO: return a DurationAnomalyTracker (which should sublclass AnomalyTracker)
+ return new AnomalyTracker(alert, mConfigKey);
+}
+
+void DurationMetricProducer::startNewProtoOutputStreamLocked(long long startTime) {
mProto = std::make_unique<ProtoOutputStream>();
mProto->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
@@ -111,16 +122,16 @@
}
unique_ptr<DurationTracker> DurationMetricProducer::createDurationTracker(
- const HashableDimensionKey& eventKey, vector<DurationBucket>& bucket) {
+ const HashableDimensionKey& eventKey) const {
switch (mMetric.aggregation_type()) {
case DurationMetric_AggregationType_SUM:
return make_unique<OringDurationTracker>(
mConfigKey, mMetric.name(), eventKey, mWizard, mConditionTrackerIndex, mNested,
- mCurrentBucketStartTimeNs, mBucketSizeNs, mAnomalyTrackers, bucket);
+ mCurrentBucketStartTimeNs, mBucketSizeNs, mAnomalyTrackers);
case DurationMetric_AggregationType_MAX_SPARSE:
return make_unique<MaxDurationTracker>(
mConfigKey, mMetric.name(), eventKey, mWizard, mConditionTrackerIndex, mNested,
- mCurrentBucketStartTimeNs, mBucketSizeNs, mAnomalyTrackers, bucket);
+ mCurrentBucketStartTimeNs, mBucketSizeNs, mAnomalyTrackers);
}
}
@@ -129,19 +140,20 @@
// DropboxWriter.
}
-void DurationMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
+void DurationMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
VLOG("Metric %s onSlicedConditionMayChange", mMetric.name().c_str());
- flushIfNeeded(eventTime);
+ flushIfNeededLocked(eventTime);
// Now for each of the on-going event, check if the condition has changed for them.
for (auto& pair : mCurrentSlicedDuration) {
pair.second->onSlicedConditionMayChange(eventTime);
}
}
-void DurationMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
+void DurationMetricProducer::onConditionChangedLocked(const bool conditionMet,
+ const uint64_t eventTime) {
VLOG("Metric %s onConditionChanged", mMetric.name().c_str());
mCondition = conditionMet;
- flushIfNeeded(eventTime);
+ flushIfNeededLocked(eventTime);
// TODO: need to populate the condition change time from the event which triggers the condition
// change, instead of using current time.
for (auto& pair : mCurrentSlicedDuration) {
@@ -149,13 +161,13 @@
}
}
-std::unique_ptr<std::vector<uint8_t>> DurationMetricProducer::onDumpReport() {
+std::unique_ptr<std::vector<uint8_t>> DurationMetricProducer::onDumpReportLocked() {
long long endTime = time(nullptr) * NS_PER_SEC;
// Dump current bucket if it's stale.
// If current bucket is still on-going, don't force dump current bucket.
// In finish(), We can force dump current bucket.
- flushIfNeeded(endTime);
+ flushIfNeededLocked(endTime);
VLOG("metric %s dump report now...", mMetric.name().c_str());
for (const auto& pair : mPastBuckets) {
@@ -167,13 +179,6 @@
continue;
}
- // If there is no duration bucket info for this key, don't include it in the report.
- // For example, duration started, but condition is never turned to true.
- // TODO: Only add the key to the map when we add duration buckets info for it.
- if (pair.second.size() == 0) {
- continue;
- }
-
long long wrapperToken =
mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
@@ -214,19 +219,19 @@
mProto->end(mProtoToken);
mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
(long long)mCurrentBucketStartTimeNs);
- std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
- startNewProtoOutputStream(endTime);
- // TODO: Properly clear the old buckets.
+ std::unique_ptr<std::vector<uint8_t>> buffer = serializeProtoLocked();
+ startNewProtoOutputStreamLocked(endTime);
+ mPastBuckets.clear();
return buffer;
}
-void DurationMetricProducer::flushIfNeeded(uint64_t eventTime) {
+void DurationMetricProducer::flushIfNeededLocked(const uint64_t& eventTime) {
if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTime) {
return;
}
VLOG("flushing...........");
for (auto it = mCurrentSlicedDuration.begin(); it != mCurrentSlicedDuration.end();) {
- if (it->second->flushIfNeeded(eventTime)) {
+ if (it->second->flushIfNeeded(eventTime, &mPastBuckets)) {
VLOG("erase bucket for key %s", it->first.c_str());
it = mCurrentSlicedDuration.erase(it);
} else {
@@ -239,7 +244,7 @@
mCurrentBucketNum += numBucketsForward;
}
-bool DurationMetricProducer::hitGuardRail(const HashableDimensionKey& newKey) {
+bool DurationMetricProducer::hitGuardRailLocked(const HashableDimensionKey& newKey) {
// the key is not new, we are good.
if (mCurrentSlicedDuration.find(newKey) != mCurrentSlicedDuration.end()) {
return false;
@@ -259,11 +264,11 @@
return false;
}
-void DurationMetricProducer::onMatchedLogEventInternal(
+void DurationMetricProducer::onMatchedLogEventInternalLocked(
const size_t matcherIndex, const HashableDimensionKey& eventKey,
const map<string, HashableDimensionKey>& conditionKeys, bool condition,
const LogEvent& event, bool scheduledPull) {
- flushIfNeeded(event.GetTimestampNs());
+ flushIfNeededLocked(event.GetTimestampNs());
if (matcherIndex == mStopAllIndex) {
for (auto& pair : mCurrentSlicedDuration) {
@@ -275,10 +280,10 @@
HashableDimensionKey atomKey = getHashableKey(getDimensionKey(event, mInternalDimension));
if (mCurrentSlicedDuration.find(eventKey) == mCurrentSlicedDuration.end()) {
- if (hitGuardRail(eventKey)) {
+ if (hitGuardRailLocked(eventKey)) {
return;
}
- mCurrentSlicedDuration[eventKey] = createDurationTracker(eventKey, mPastBuckets[eventKey]);
+ mCurrentSlicedDuration[eventKey] = createDurationTracker(eventKey);
}
auto it = mCurrentSlicedDuration.find(eventKey);
@@ -290,7 +295,7 @@
}
}
-size_t DurationMetricProducer::byteSize() const {
+size_t DurationMetricProducer::byteSizeLocked() const {
size_t totalSize = 0;
for (const auto& pair : mPastBuckets) {
totalSize += pair.second.size() * kBucketSize;
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 5b5373e..4bf9d1c 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -45,41 +45,50 @@
virtual ~DurationMetricProducer();
- void onConditionChanged(const bool conditionMet, const uint64_t eventTime) override;
+ virtual sp<AnomalyTracker> createAnomalyTracker(const Alert &alert) override;
void finish() override;
- void flushIfNeeded(const uint64_t newEventTime) override;
-
- // TODO: Pass a timestamp as a parameter in onDumpReport.
- std::unique_ptr<std::vector<uint8_t>> onDumpReport() override;
-
- void onSlicedConditionMayChange(const uint64_t eventTime) override;
-
- size_t byteSize() const override;
// TODO: Implement this later.
- virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
+ virtual void notifyAppUpgrade(const string& apk, const int uid, const int64_t version)
+ override{};
// TODO: Implement this later.
virtual void notifyAppRemoved(const string& apk, const int uid) override{};
protected:
- void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey,
- const std::map<std::string, HashableDimensionKey>& conditionKeys,
- bool condition, const LogEvent& event,
- bool scheduledPull) override;
-
- void startNewProtoOutputStream(long long timestamp) override;
+ void onMatchedLogEventInternalLocked(
+ const size_t matcherIndex, const HashableDimensionKey& eventKey,
+ const std::map<std::string, HashableDimensionKey>& conditionKeys, bool condition,
+ const LogEvent& event, bool scheduledPull) override;
private:
+ // TODO: Pass a timestamp as a parameter in onDumpReport.
+ std::unique_ptr<std::vector<uint8_t>> onDumpReportLocked() override;
+
+ // Internal interface to handle condition change.
+ void onConditionChangedLocked(const bool conditionMet, const uint64_t eventTime) override;
+
+ // Internal interface to handle sliced condition change.
+ void onSlicedConditionMayChangeLocked(const uint64_t eventTime) override;
+
+ // Internal function to calculate the current used bytes.
+ size_t byteSizeLocked() const override;
+
+ // Util function to flush the old packet.
+ void flushIfNeededLocked(const uint64_t& eventTime);
+
+ // Util function to init/reset the proto output stream.
+ void startNewProtoOutputStreamLocked(long long timestamp);
+
const DurationMetric mMetric;
- // Index of the SimpleLogEntryMatcher which defines the start.
+ // Index of the SimpleAtomMatcher which defines the start.
const size_t mStartIndex;
- // Index of the SimpleLogEntryMatcher which defines the stop.
+ // Index of the SimpleAtomMatcher which defines the stop.
const size_t mStopIndex;
- // Index of the SimpleLogEntryMatcher which defines the stop all for all dimensions.
+ // Index of the SimpleAtomMatcher which defines the stop all for all dimensions.
const size_t mStopAllIndex;
// nest counting -- for the same key, stops must match the number of starts to make real stop
@@ -96,14 +105,19 @@
std::unordered_map<HashableDimensionKey, std::unique_ptr<DurationTracker>>
mCurrentSlicedDuration;
- std::unique_ptr<DurationTracker> createDurationTracker(const HashableDimensionKey& eventKey,
- std::vector<DurationBucket>& bucket);
- bool hitGuardRail(const HashableDimensionKey& newKey);
+ // Helper function to create a duration tracker given the metric aggregation type.
+ std::unique_ptr<DurationTracker> createDurationTracker(
+ const HashableDimensionKey& eventKey) const;
+
+ // Util function to check whether the specified dimension hits the guardrail.
+ bool hitGuardRailLocked(const HashableDimensionKey& newKey);
static const size_t kBucketSize = sizeof(DurationBucket{});
+
+ FRIEND_TEST(DurationMetricTrackerTest, TestNoCondition);
+ FRIEND_TEST(DurationMetricTrackerTest, TestNonSlicedCondition);
};
} // namespace statsd
} // namespace os
} // namespace android
-
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 95a18f7..8bdc9e3 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -62,7 +62,7 @@
mConditionSliced = true;
}
- startNewProtoOutputStream(mStartTimeNs);
+ startNewProtoOutputStreamLocked(mStartTimeNs);
VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
@@ -72,7 +72,7 @@
VLOG("~EventMetricProducer() called");
}
-void EventMetricProducer::startNewProtoOutputStream(long long startTime) {
+void EventMetricProducer::startNewProtoOutputStreamLocked(long long startTime) {
mProto = std::make_unique<ProtoOutputStream>();
// TODO: We need to auto-generate the field IDs for StatsLogReport, EventMetricData,
// and StatsEvent.
@@ -84,29 +84,30 @@
void EventMetricProducer::finish() {
}
-void EventMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
+void EventMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
}
-std::unique_ptr<std::vector<uint8_t>> EventMetricProducer::onDumpReport() {
+std::unique_ptr<std::vector<uint8_t>> EventMetricProducer::onDumpReportLocked() {
long long endTime = time(nullptr) * NS_PER_SEC;
mProto->end(mProtoToken);
mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, endTime);
size_t bufferSize = mProto->size();
VLOG("metric %s dump report now... proto size: %zu ", mMetric.name().c_str(), bufferSize);
- std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
+ std::unique_ptr<std::vector<uint8_t>> buffer = serializeProtoLocked();
- startNewProtoOutputStream(endTime);
+ startNewProtoOutputStreamLocked(endTime);
return buffer;
}
-void EventMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
+void EventMetricProducer::onConditionChangedLocked(const bool conditionMet,
+ const uint64_t eventTime) {
VLOG("Metric %s onConditionChanged", mMetric.name().c_str());
mCondition = conditionMet;
}
-void EventMetricProducer::onMatchedLogEventInternal(
+void EventMetricProducer::onMatchedLogEventInternalLocked(
const size_t matcherIndex, const HashableDimensionKey& eventKey,
const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition,
const LogEvent& event, bool scheduledPull) {
@@ -123,7 +124,7 @@
mProto->end(wrapperToken);
}
-size_t EventMetricProducer::byteSize() const {
+size_t EventMetricProducer::byteSizeLocked() const {
return mProto->bytesWritten();
}
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 33a9510..da3b3ca 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -40,33 +40,35 @@
virtual ~EventMetricProducer();
- void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey,
- const std::map<std::string, HashableDimensionKey>& conditionKey,
- bool condition, const LogEvent& event,
- bool scheduledPull) override;
-
- void onConditionChanged(const bool conditionMet, const uint64_t eventTime) override;
-
void finish() override;
- void flushIfNeeded(const uint64_t newEventTime) override {
- }
-
- // TODO: Pass a timestamp as a parameter in onDumpReport.
- std::unique_ptr<std::vector<uint8_t>> onDumpReport() override;
-
- void onSlicedConditionMayChange(const uint64_t eventTime) override;
-
- size_t byteSize() const override;
// TODO: Implement this later.
- virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
+ virtual void notifyAppUpgrade(const string& apk, const int uid, const int64_t version)
+ override{};
// TODO: Implement this later.
virtual void notifyAppRemoved(const string& apk, const int uid) override{};
protected:
- void startNewProtoOutputStream(long long timestamp) override;
+ void startNewProtoOutputStreamLocked(long long timestamp);
private:
+ void onMatchedLogEventInternalLocked(
+ const size_t matcherIndex, const HashableDimensionKey& eventKey,
+ const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition,
+ const LogEvent& event, bool scheduledPull) override;
+
+ // TODO: Pass a timestamp as a parameter in onDumpReport.
+ std::unique_ptr<std::vector<uint8_t>> onDumpReportLocked() override;
+
+ // Internal interface to handle condition change.
+ void onConditionChangedLocked(const bool conditionMet, const uint64_t eventTime) override;
+
+ // Internal interface to handle sliced condition change.
+ void onSlicedConditionMayChangeLocked(const uint64_t eventTime) override;
+
+ // Internal function to calculate the current used bytes.
+ size_t byteSizeLocked() const override;
+
const EventMetric mMetric;
};
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 1791654..1f6bd58b 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -91,7 +91,7 @@
metric.bucket().bucket_size_millis());
}
- startNewProtoOutputStream(mStartTimeNs);
+ startNewProtoOutputStreamLocked(mStartTimeNs);
VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
@@ -99,9 +99,12 @@
GaugeMetricProducer::~GaugeMetricProducer() {
VLOG("~GaugeMetricProducer() called");
+ if (mPullTagId != -1) {
+ mStatsPullerManager.UnRegisterReceiver(mPullTagId, this);
+ }
}
-void GaugeMetricProducer::startNewProtoOutputStream(long long startTime) {
+void GaugeMetricProducer::startNewProtoOutputStreamLocked(long long startTime) {
mProto = std::make_unique<ProtoOutputStream>();
mProto->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
@@ -111,13 +114,13 @@
void GaugeMetricProducer::finish() {
}
-std::unique_ptr<std::vector<uint8_t>> GaugeMetricProducer::onDumpReport() {
+std::unique_ptr<std::vector<uint8_t>> GaugeMetricProducer::onDumpReportLocked() {
VLOG("gauge metric %s dump report now...", mMetric.name().c_str());
// Dump current bucket if it's stale.
// If current bucket is still on-going, don't force dump current bucket.
// In finish(), We can force dump current bucket.
- flushIfNeeded(time(nullptr) * NS_PER_SEC);
+ flushIfNeededLocked(time(nullptr) * NS_PER_SEC);
for (const auto& pair : mPastBuckets) {
const HashableDimensionKey& hashableKey = pair.first;
@@ -167,9 +170,9 @@
mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
(long long)mCurrentBucketStartTimeNs);
- std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
+ std::unique_ptr<std::vector<uint8_t>> buffer = serializeProtoLocked();
- startNewProtoOutputStream(time(nullptr) * NS_PER_SEC);
+ startNewProtoOutputStreamLocked(time(nullptr) * NS_PER_SEC);
mPastBuckets.clear();
return buffer;
@@ -177,10 +180,10 @@
// TODO: Clear mDimensionKeyMap once the report is dumped.
}
-void GaugeMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
- AutoMutex _l(mLock);
+void GaugeMetricProducer::onConditionChangedLocked(const bool conditionMet,
+ const uint64_t eventTime) {
VLOG("Metric %s onConditionChanged", mMetric.name().c_str());
- flushIfNeeded(eventTime);
+ flushIfNeededLocked(eventTime);
mCondition = conditionMet;
// Push mode. No need to proactively pull the gauge data.
@@ -200,12 +203,12 @@
return;
}
for (const auto& data : allData) {
- onMatchedLogEvent(0, *data, false /*scheduledPull*/);
+ onMatchedLogEventLocked(0, *data, false /*scheduledPull*/);
}
- flushIfNeeded(eventTime);
+ flushIfNeededLocked(eventTime);
}
-void GaugeMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
+void GaugeMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
VLOG("Metric %s onSlicedConditionMayChange", mMetric.name().c_str());
}
@@ -221,13 +224,14 @@
}
void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
- AutoMutex mutex(mLock);
+ std::lock_guard<std::mutex> lock(mMutex);
+
for (const auto& data : allData) {
- onMatchedLogEvent(0, *data, true /*scheduledPull*/);
+ onMatchedLogEventLocked(0, *data, true /*scheduledPull*/);
}
}
-bool GaugeMetricProducer::hitGuardRail(const HashableDimensionKey& newKey) {
+bool GaugeMetricProducer::hitGuardRailLocked(const HashableDimensionKey& newKey) {
if (mCurrentSlicedBucket->find(newKey) != mCurrentSlicedBucket->end()) {
return false;
}
@@ -247,7 +251,7 @@
return false;
}
-void GaugeMetricProducer::onMatchedLogEventInternal(
+void GaugeMetricProducer::onMatchedLogEventInternalLocked(
const size_t matcherIndex, const HashableDimensionKey& eventKey,
const map<string, HashableDimensionKey>& conditionKey, bool condition,
const LogEvent& event, bool scheduledPull) {
@@ -263,7 +267,7 @@
// When the event happens in a new bucket, flush the old buckets.
if (eventTimeNs >= mCurrentBucketStartTimeNs + mBucketSizeNs) {
- flushIfNeeded(eventTimeNs);
+ flushIfNeededLocked(eventTimeNs);
}
// For gauge metric, we just simply use the first gauge in the given bucket.
@@ -272,7 +276,7 @@
}
const long gauge = getGauge(event);
if (gauge >= 0) {
- if (hitGuardRail(eventKey)) {
+ if (hitGuardRailLocked(eventKey)) {
return;
}
(*mCurrentSlicedBucket)[eventKey] = gauge;
@@ -287,7 +291,7 @@
// bucket.
// if data is pushed, onMatchedLogEvent will only be called through onConditionChanged() inside
// the GaugeMetricProducer while holding the lock.
-void GaugeMetricProducer::flushIfNeeded(const uint64_t eventTimeNs) {
+void GaugeMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
if (eventTimeNs < mCurrentBucketStartTimeNs + mBucketSizeNs) {
return;
}
@@ -320,7 +324,7 @@
(long long)mCurrentBucketStartTimeNs);
}
-size_t GaugeMetricProducer::byteSize() const {
+size_t GaugeMetricProducer::byteSizeLocked() const {
size_t totalSize = 0;
for (const auto& pair : mPastBuckets) {
totalSize += pair.second.size() * kBucketSize;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index f344303..36705b1 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -56,41 +56,48 @@
// Handles when the pulled data arrives.
void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) override;
- void onConditionChanged(const bool conditionMet, const uint64_t eventTime) override;
- void onSlicedConditionMayChange(const uint64_t eventTime) override;
-
void finish() override;
- void flushIfNeeded(const uint64_t newEventTime) override;
-
- // TODO: Pass a timestamp as a parameter in onDumpReport.
- std::unique_ptr<std::vector<uint8_t>> onDumpReport() override;
-
- size_t byteSize() const override;
// TODO: Implement this later.
- virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
+ virtual void notifyAppUpgrade(const string& apk, const int uid, const int64_t version)
+ override{};
// TODO: Implement this later.
virtual void notifyAppRemoved(const string& apk, const int uid) override{};
protected:
- void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey,
- const std::map<std::string, HashableDimensionKey>& conditionKey,
- bool condition, const LogEvent& event,
- bool scheduledPull) override;
-
- void startNewProtoOutputStream(long long timestamp) override;
+ void onMatchedLogEventInternalLocked(
+ const size_t matcherIndex, const HashableDimensionKey& eventKey,
+ const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition,
+ const LogEvent& event, bool scheduledPull) override;
private:
+ // TODO: Pass a timestamp as a parameter in onDumpReport.
+ std::unique_ptr<std::vector<uint8_t>> onDumpReportLocked() override;
+
+ // Internal interface to handle condition change.
+ void onConditionChangedLocked(const bool conditionMet, const uint64_t eventTime) override;
+
+ // Internal interface to handle sliced condition change.
+ void onSlicedConditionMayChangeLocked(const uint64_t eventTime) override;
+
+ // Internal function to calculate the current used bytes.
+ size_t byteSizeLocked() const override;
+
+ // Util function to flush the old packet.
+ void flushIfNeededLocked(const uint64_t& eventTime);
+
+ // Util function to init/reset the proto output stream.
+ void startNewProtoOutputStreamLocked(long long timestamp);
+
// The default bucket size for gauge metric is 1 second.
static const uint64_t kDefaultGaugemBucketSizeNs = 1000 * 1000 * 1000;
+
const GaugeMetric mMetric;
StatsPullerManager mStatsPullerManager;
// tagId for pulled data. -1 if this is not pulled
const int mPullTagId;
- Mutex mLock;
-
// Save the past buckets and we can clear when the StatsLogReport is dumped.
// TODO: Add a lock to mPastBuckets.
std::unordered_map<HashableDimensionKey, std::vector<GaugeBucket>> mPastBuckets;
@@ -100,7 +107,8 @@
int64_t getGauge(const LogEvent& event);
- bool hitGuardRail(const HashableDimensionKey& newKey);
+ // Util function to check whether the specified dimension hits the guardrail.
+ bool hitGuardRailLocked(const HashableDimensionKey& newKey);
static const size_t kBucketSize = sizeof(GaugeBucket{});
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 62fb632..7e78a85 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -21,8 +21,8 @@
using std::map;
-void MetricProducer::onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event,
- bool scheduledPull) {
+void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event,
+ bool scheduledPull) {
uint64_t eventTimeNs = event.GetTimestampNs();
// this is old event, maybe statsd restarted?
if (eventTimeNs < mStartTimeNs) {
@@ -60,11 +60,11 @@
condition = mCondition;
}
- onMatchedLogEventInternal(matcherIndex, eventKey, conditionKeys, condition, event,
- scheduledPull);
+ onMatchedLogEventInternalLocked(matcherIndex, eventKey, conditionKeys, condition, event,
+ scheduledPull);
}
-std::unique_ptr<std::vector<uint8_t>> MetricProducer::serializeProto() {
+std::unique_ptr<std::vector<uint8_t>> MetricProducer::serializeProtoLocked() {
size_t bufferSize = mProto->size();
std::unique_ptr<std::vector<uint8_t>> buffer(new std::vector<uint8_t>(bufferSize));
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index b22ff6f..adeb3cd 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -17,6 +17,8 @@
#ifndef METRIC_PRODUCER_H
#define METRIC_PRODUCER_H
+#include <shared_mutex>
+
#include "anomaly/AnomalyTracker.h"
#include "condition/ConditionWizard.h"
#include "config/ConfigKey.h"
@@ -52,39 +54,65 @@
virtual ~MetricProducer(){};
// Consume the parsed stats log entry that already matched the "what" of the metric.
- void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event, bool scheduledPull);
+ void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event, bool scheduledPull) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ onMatchedLogEventLocked(matcherIndex, event, scheduledPull);
+ }
- virtual void onConditionChanged(const bool condition, const uint64_t eventTime) = 0;
+ void onConditionChanged(const bool condition, const uint64_t eventTime) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ onConditionChangedLocked(condition, eventTime);
+ }
- virtual void onSlicedConditionMayChange(const uint64_t eventTime) = 0;
+ void onSlicedConditionMayChange(const uint64_t eventTime) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ onSlicedConditionMayChangeLocked(eventTime);
+ }
+
+ bool isConditionSliced() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mConditionSliced;
+ };
// This is called when the metric collecting is done, e.g., when there is a new configuration
// coming. MetricProducer should do the clean up, and dump existing data to dropbox.
virtual void finish() = 0;
- virtual void flushIfNeeded(const uint64_t newEventTime) = 0;
// TODO: Pass a timestamp as a parameter in onDumpReport and update all its
// implementations.
// onDumpReport returns the proto-serialized output and clears the previously stored contents.
- virtual std::unique_ptr<std::vector<uint8_t>> onDumpReport() = 0;
-
- virtual bool isConditionSliced() const {
- return mConditionSliced;
- };
+ std::unique_ptr<std::vector<uint8_t>> onDumpReport() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return onDumpReportLocked();
+ }
// Returns the memory in bytes currently used to store this metric's data. Does not change
// state.
- virtual size_t byteSize() const = 0;
+ size_t byteSize() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return byteSizeLocked();
+ }
+
+ virtual sp<AnomalyTracker> createAnomalyTracker(const Alert &alert) {
+ return new AnomalyTracker(alert, mConfigKey);
+ }
void addAnomalyTracker(sp<AnomalyTracker> tracker) {
+ std::lock_guard<std::mutex> lock(mMutex);
mAnomalyTrackers.push_back(tracker);
}
int64_t getBuckeSizeInNs() const {
+ std::lock_guard<std::mutex> lock(mMutex);
return mBucketSizeNs;
}
protected:
+ virtual void onConditionChangedLocked(const bool condition, const uint64_t eventTime) = 0;
+ virtual void onSlicedConditionMayChangeLocked(const uint64_t eventTime) = 0;
+ virtual std::unique_ptr<std::vector<uint8_t>> onDumpReportLocked() = 0;
+ virtual size_t byteSizeLocked() const = 0;
+
const ConfigKey mConfigKey;
const uint64_t mStartTimeNs;
@@ -109,7 +137,7 @@
// that StatsLogReport wants.
std::unordered_map<HashableDimensionKey, std::vector<KeyValuePair>> mDimensionKeyMap;
- std::vector<EventConditionLink> mConditionLinks;
+ std::vector<MetricConditionLink> mConditionLinks;
std::vector<sp<AnomalyTracker>> mAnomalyTrackers;
@@ -121,25 +149,31 @@
* [eventKey]: the extracted dimension key for the final output. if the metric doesn't have
* dimensions, it will be DEFAULT_DIMENSION_KEY
* [conditionKey]: the keys of conditions which should be used to query the condition for this
- * target event (from EventConditionLink). This is passed to individual metrics
+ * target event (from MetricConditionLink). This is passed to individual metrics
* because DurationMetric needs it to be cached.
* [condition]: whether condition is met. If condition is sliced, this is the result coming from
* query with ConditionWizard; If condition is not sliced, this is the
* nonSlicedCondition.
* [event]: the log event, just in case the metric needs its data, e.g., EventMetric.
*/
- virtual void onMatchedLogEventInternal(
+ virtual void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const HashableDimensionKey& eventKey,
const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition,
const LogEvent& event, bool scheduledPull) = 0;
+ // Consume the parsed stats log entry that already matched the "what" of the metric.
+ void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event,
+ bool scheduledPull);
+
std::unique_ptr<android::util::ProtoOutputStream> mProto;
long long mProtoToken;
- virtual void startNewProtoOutputStream(long long timestamp) = 0;
+ // Read/Write mutex to make the producer thread-safe.
+ // TODO(yanglu): replace with std::shared_mutex when available in libc++.
+ mutable std::mutex mMutex;
- std::unique_ptr<std::vector<uint8_t>> serializeProto();
+ std::unique_ptr<std::vector<uint8_t>> serializeProtoLocked();
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index c866951..9fdc6fa 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -39,7 +39,7 @@
MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config) : mConfigKey(key) {
mConfigValid =
- initStatsdConfig(key, config, mTagIds, mAllLogEntryMatchers, mAllConditionTrackers,
+ initStatsdConfig(key, config, mTagIds, mAllAtomMatchers, mAllConditionTrackers,
mAllMetricProducers, mAllAnomalyTrackers, mConditionToMetricMap,
mTrackerToMetricMap, mTrackerToConditionMap);
@@ -47,11 +47,11 @@
// no matter whether this config is valid, log it in the stats.
StatsdStats::getInstance().noteConfigReceived(key, mAllMetricProducers.size(),
mAllConditionTrackers.size(),
- mAllLogEntryMatchers.size(), 0, mConfigValid);
+ mAllAtomMatchers.size(), 0, mConfigValid);
// Guardrail. Reject the config if it's too big.
if (mAllMetricProducers.size() > StatsdStats::kMaxMetricCountPerConfig ||
mAllConditionTrackers.size() > StatsdStats::kMaxConditionCountPerConfig ||
- mAllLogEntryMatchers.size() > StatsdStats::kMaxMatcherCountPerConfig) {
+ mAllAtomMatchers.size() > StatsdStats::kMaxMatcherCountPerConfig) {
ALOGE("This config is too big! Reject!");
mConfigValid = false;
}
@@ -95,10 +95,10 @@
return;
}
- vector<MatchingState> matcherCache(mAllLogEntryMatchers.size(), MatchingState::kNotComputed);
+ vector<MatchingState> matcherCache(mAllAtomMatchers.size(), MatchingState::kNotComputed);
- for (auto& matcher : mAllLogEntryMatchers) {
- matcher->onLogEvent(event, mAllLogEntryMatchers, matcherCache);
+ for (auto& matcher : mAllAtomMatchers) {
+ matcher->onLogEvent(event, mAllAtomMatchers, matcherCache);
}
// A bitmap to see which ConditionTracker needs to be re-evaluated.
@@ -142,25 +142,25 @@
// metric cares about sliced conditions, and it may have changed. Send
// notification, and the metric can query the sliced conditions that are
// interesting to it.
- } else if (mAllMetricProducers[metricIndex]->isConditionSliced()) {
+ } else {
mAllMetricProducers[metricIndex]->onSlicedConditionMayChange(eventTime);
}
}
}
}
- // For matched LogEntryMatchers, tell relevant metrics that a matched event has come.
- for (size_t i = 0; i < mAllLogEntryMatchers.size(); i++) {
+ // For matched AtomMatchers, tell relevant metrics that a matched event has come.
+ for (size_t i = 0; i < mAllAtomMatchers.size(); i++) {
if (matcherCache[i] == MatchingState::kMatched) {
StatsdStats::getInstance().noteMatcherMatched(mConfigKey,
- mAllLogEntryMatchers[i]->getName());
+ mAllAtomMatchers[i]->getName());
auto pair = mTrackerToMetricMap.find(i);
if (pair != mTrackerToMetricMap.end()) {
auto& metricList = pair->second;
for (const int metricIndex : metricList) {
// pushed metrics are never scheduled pulls
- mAllMetricProducers[metricIndex]->onMatchedLogEvent(
- i, event, false /* schedulePull */);
+ mAllMetricProducers[metricIndex]->onMatchedLogEvent(i, event,
+ false /* schedulePull */);
}
}
}
@@ -168,9 +168,9 @@
}
void MetricsManager::onAnomalyAlarmFired(const uint64_t timestampNs,
- sp<const AnomalyAlarm> anomaly) {
+ unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& anomalySet) {
for (const auto& itr : mAllAnomalyTrackers) {
- itr->declareAnomaly(timestampNs);
+ itr->informAlarmsFired(timestampNs, anomalySet);
}
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 517831d..86c4733 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -36,7 +36,7 @@
public:
MetricsManager(const ConfigKey& configKey, const StatsdConfig& config);
- ~MetricsManager();
+ virtual ~MetricsManager();
// Return whether the configuration is valid.
bool isConfigValid() const;
@@ -46,16 +46,17 @@
// Called when everything should wrap up. We are about to finish (e.g., new config comes).
void finish();
- void onAnomalyAlarmFired(const uint64_t timestampNs, sp<const AnomalyAlarm> anomaly);
+ void onAnomalyAlarmFired(const uint64_t timestampNs,
+ unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& anomalySet);
void setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor);
// Config source owner can call onDumpReport() to get all the metrics collected.
- std::vector<std::unique_ptr<std::vector<uint8_t>>> onDumpReport();
+ virtual std::vector<std::unique_ptr<std::vector<uint8_t>>> onDumpReport();
// Computes the total byte size of all metrics managed by a single config source.
// Does not change the state.
- size_t byteSize();
+ virtual size_t byteSize();
private:
const ConfigKey mConfigKey;
@@ -70,8 +71,8 @@
// holds A's sp. (2) When we evaluate matcher results, or condition results, we can quickly get
// the related results from a cache using the index.
- // Hold all the log entry matchers from the config.
- std::vector<sp<LogMatchingTracker>> mAllLogEntryMatchers;
+ // Hold all the atom matchers from the config.
+ std::vector<sp<LogMatchingTracker>> mAllAtomMatchers;
// Hold all the conditions from the config.
std::vector<sp<ConditionTracker>> mAllConditionTrackers;
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 66c8419..977aa88 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -98,7 +98,7 @@
metric.bucket().bucket_size_millis());
}
- startNewProtoOutputStream(mStartTimeNs);
+ startNewProtoOutputStreamLocked(mStartTimeNs);
VLOG("value metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
@@ -120,7 +120,7 @@
}
}
-void ValueMetricProducer::startNewProtoOutputStream(long long startTime) {
+void ValueMetricProducer::startNewProtoOutputStreamLocked(long long startTime) {
mProto = std::make_unique<ProtoOutputStream>();
mProto->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
@@ -132,11 +132,11 @@
// DropboxWriter.
}
-void ValueMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
+void ValueMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
VLOG("Metric %s onSlicedConditionMayChange", mMetric.name().c_str());
}
-std::unique_ptr<std::vector<uint8_t>> ValueMetricProducer::onDumpReport() {
+std::unique_ptr<std::vector<uint8_t>> ValueMetricProducer::onDumpReportLocked() {
VLOG("metric %s dump report now...", mMetric.name().c_str());
for (const auto& pair : mPastBuckets) {
@@ -187,9 +187,9 @@
(long long)mCurrentBucketStartTimeNs);
VLOG("metric %s dump report now...", mMetric.name().c_str());
- std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
+ std::unique_ptr<std::vector<uint8_t>> buffer = serializeProtoLocked();
- startNewProtoOutputStream(time(nullptr) * NS_PER_SEC);
+ startNewProtoOutputStreamLocked(time(nullptr) * NS_PER_SEC);
mPastBuckets.clear();
return buffer;
@@ -197,8 +197,7 @@
// TODO: Clear mDimensionKeyMap once the report is dumped.
}
-void ValueMetricProducer::onConditionChanged(const bool condition, const uint64_t eventTime) {
- AutoMutex _l(mLock);
+void ValueMetricProducer::onConditionChangedLocked(const bool condition, const uint64_t eventTime) {
mCondition = condition;
if (mPullTagId != -1) {
@@ -215,16 +214,17 @@
return;
}
for (const auto& data : allData) {
- onMatchedLogEvent(0, *data, false);
+ onMatchedLogEventLocked(0, *data, false);
}
- flushIfNeeded(eventTime);
+ flushIfNeededLocked(eventTime);
}
return;
}
}
void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mMutex);
+
if (mCondition == true || !mMetric.has_condition()) {
if (allData.size() == 0) {
return;
@@ -232,16 +232,16 @@
uint64_t eventTime = allData.at(0)->GetTimestampNs();
// alarm is not accurate and might drift.
if (eventTime > mCurrentBucketStartTimeNs + mBucketSizeNs * 3 / 2) {
- flushIfNeeded(eventTime);
+ flushIfNeededLocked(eventTime);
}
for (const auto& data : allData) {
- onMatchedLogEvent(0, *data, true);
+ onMatchedLogEventLocked(0, *data, true);
}
- flushIfNeeded(eventTime);
+ flushIfNeededLocked(eventTime);
}
}
-bool ValueMetricProducer::hitGuardRail(const HashableDimensionKey& newKey) {
+bool ValueMetricProducer::hitGuardRailLocked(const HashableDimensionKey& newKey) {
// ===========GuardRail==============
// 1. Report the tuple count if the tuple count > soft limit
if (mCurrentSlicedBucket.find(newKey) != mCurrentSlicedBucket.end()) {
@@ -262,7 +262,7 @@
return false;
}
-void ValueMetricProducer::onMatchedLogEventInternal(
+void ValueMetricProducer::onMatchedLogEventInternalLocked(
const size_t matcherIndex, const HashableDimensionKey& eventKey,
const map<string, HashableDimensionKey>& conditionKey, bool condition,
const LogEvent& event, bool scheduledPull) {
@@ -273,7 +273,7 @@
return;
}
- if (hitGuardRail(eventKey)) {
+ if (hitGuardRailLocked(eventKey)) {
return;
}
Interval& interval = mCurrentSlicedBucket[eventKey];
@@ -308,7 +308,7 @@
}
}
} else {
- flushIfNeeded(eventTimeNs);
+ flushIfNeededLocked(eventTimeNs);
interval.raw.push_back(make_pair(value, 0));
}
}
@@ -324,7 +324,7 @@
}
}
-void ValueMetricProducer::flushIfNeeded(const uint64_t eventTimeNs) {
+void ValueMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTimeNs) {
VLOG("eventTime is %lld, less than next bucket start time %lld", (long long)eventTimeNs,
(long long)(mCurrentBucketStartTimeNs + mBucketSizeNs));
@@ -372,7 +372,7 @@
(long long)mCurrentBucketStartTimeNs);
}
-size_t ValueMetricProducer::byteSize() const {
+size_t ValueMetricProducer::byteSizeLocked() const {
size_t totalSize = 0;
for (const auto& pair : mPastBuckets) {
totalSize += pair.second.size() * kBucketSize;
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index a024bd8..a2efd3f 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -44,34 +44,41 @@
virtual ~ValueMetricProducer();
- void onConditionChanged(const bool condition, const uint64_t eventTime) override;
-
void finish() override;
- void flushIfNeeded(const uint64_t eventTimeNs) override;
-
- // TODO: Pass a timestamp as a parameter in onDumpReport.
- std::unique_ptr<std::vector<uint8_t>> onDumpReport() override;
-
- void onSlicedConditionMayChange(const uint64_t eventTime);
void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) override;
- size_t byteSize() const override;
-
// TODO: Implement this later.
- virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
+ virtual void notifyAppUpgrade(const string& apk, const int uid, const int64_t version)
+ override{};
// TODO: Implement this later.
virtual void notifyAppRemoved(const string& apk, const int uid) override{};
protected:
- void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey,
- const std::map<std::string, HashableDimensionKey>& conditionKey,
- bool condition, const LogEvent& event,
- bool scheduledPull) override;
-
- void startNewProtoOutputStream(long long timestamp) override;
+ void onMatchedLogEventInternalLocked(
+ const size_t matcherIndex, const HashableDimensionKey& eventKey,
+ const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition,
+ const LogEvent& event, bool scheduledPull) override;
private:
+ // TODO: Pass a timestamp as a parameter in onDumpReport.
+ std::unique_ptr<std::vector<uint8_t>> onDumpReportLocked() override;
+
+ // Internal interface to handle condition change.
+ void onConditionChangedLocked(const bool conditionMet, const uint64_t eventTime) override;
+
+ // Internal interface to handle sliced condition change.
+ void onSlicedConditionMayChangeLocked(const uint64_t eventTime) override;
+
+ // Internal function to calculate the current used bytes.
+ size_t byteSizeLocked() const override;
+
+ // Util function to flush the old packet.
+ void flushIfNeededLocked(const uint64_t& eventTime);
+
+ // Util function to init/reset the proto output stream.
+ void startNewProtoOutputStreamLocked(long long timestamp);
+
const ValueMetric mMetric;
std::shared_ptr<StatsPullerManager> mStatsPullerManager;
@@ -82,8 +89,6 @@
const int pullTagId, const uint64_t startTimeNs,
std::shared_ptr<StatsPullerManager> statsPullerManager);
- Mutex mLock;
-
// tagId for pulled data. -1 if this is not pulled
const int mPullTagId;
@@ -104,7 +109,8 @@
long get_value(const LogEvent& event);
- bool hitGuardRail(const HashableDimensionKey& newKey);
+ // Util function to check whether the specified dimension hits the guardrail.
+ bool hitGuardRailLocked(const HashableDimensionKey& newKey);
static const size_t kBucketSize = sizeof(ValueBucket{});
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 834f7f5..3c714b3 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -63,8 +63,7 @@
DurationTracker(const ConfigKey& key, const string& name, const HashableDimensionKey& eventKey,
sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
- const std::vector<sp<AnomalyTracker>>& anomalyTrackers,
- std::vector<DurationBucket>& bucket)
+ const std::vector<sp<AnomalyTracker>>& anomalyTrackers)
: mConfigKey(key),
mName(name),
mEventKey(eventKey),
@@ -73,7 +72,6 @@
mBucketSizeNs(bucketSizeNs),
mNested(nesting),
mCurrentBucketStartTimeNs(currentBucketStartNs),
- mBucket(bucket),
mDuration(0),
mCurrentBucketNum(0),
mAnomalyTrackers(anomalyTrackers){};
@@ -91,7 +89,9 @@
// Flush stale buckets if needed, and return true if the tracker has no on-going duration
// events, so that the owner can safely remove the tracker.
- virtual bool flushIfNeeded(uint64_t timestampNs) = 0;
+ virtual bool flushIfNeeded(
+ uint64_t timestampNs,
+ std::unordered_map<HashableDimensionKey, std::vector<DurationBucket>>* output) = 0;
// Predict the anomaly timestamp given the current status.
virtual int64_t predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
@@ -159,8 +159,6 @@
uint64_t mCurrentBucketStartTimeNs;
- std::vector<DurationBucket>& mBucket; // where to write output
-
int64_t mDuration; // current recorded duration result
uint64_t mCurrentBucketNum;
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index 4b346dd..08c9135 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -28,10 +28,9 @@
const HashableDimensionKey& eventKey,
sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
- const std::vector<sp<AnomalyTracker>>& anomalyTrackers,
- std::vector<DurationBucket>& bucket)
+ const std::vector<sp<AnomalyTracker>>& anomalyTrackers)
: DurationTracker(key, name, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
- bucketSizeNs, anomalyTrackers, bucket) {
+ bucketSizeNs, anomalyTrackers) {
}
bool MaxDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) {
@@ -145,7 +144,8 @@
}
}
-bool MaxDurationTracker::flushIfNeeded(uint64_t eventTime) {
+bool MaxDurationTracker::flushIfNeeded(
+ uint64_t eventTime, unordered_map<HashableDimensionKey, vector<DurationBucket>>* output) {
if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTime) {
return false;
}
@@ -202,7 +202,7 @@
if (mDuration != 0) {
info.mDuration = mDuration;
- mBucket.push_back(info);
+ (*output)[mEventKey].push_back(info);
addPastBucketToAnomalyTrackers(info.mDuration, info.mBucketNum);
VLOG(" final duration for last bucket: %lld", (long long)mDuration);
}
@@ -215,7 +215,7 @@
info.mBucketEndNs = endTime + mBucketSizeNs * i;
info.mBucketNum = mCurrentBucketNum + i;
info.mDuration = mBucketSizeNs;
- mBucket.push_back(info);
+ (*output)[mEventKey].push_back(info);
addPastBucketToAnomalyTrackers(info.mDuration, info.mBucketNum);
VLOG(" filling gap bucket with duration %lld", (long long)mBucketSizeNs);
}
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
index e0d1466..10eddb8 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -32,15 +32,16 @@
const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard,
int conditionIndex, bool nesting, uint64_t currentBucketStartNs,
uint64_t bucketSizeNs,
- const std::vector<sp<AnomalyTracker>>& anomalyTrackers,
- std::vector<DurationBucket>& bucket);
+ const std::vector<sp<AnomalyTracker>>& anomalyTrackers);
void noteStart(const HashableDimensionKey& key, bool condition, const uint64_t eventTime,
const ConditionKey& conditionKey) override;
void noteStop(const HashableDimensionKey& key, const uint64_t eventTime,
const bool stopAll) override;
void noteStopAll(const uint64_t eventTime) override;
- bool flushIfNeeded(uint64_t timestampNs) override;
+ bool flushIfNeeded(
+ uint64_t timestampNs,
+ std::unordered_map<HashableDimensionKey, std::vector<DurationBucket>>* output) override;
void onSlicedConditionMayChange(const uint64_t timestamp) override;
void onConditionChanged(bool condition, const uint64_t timestamp) override;
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index 22c33d6..8122744 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -29,10 +29,9 @@
sp<ConditionWizard> wizard, int conditionIndex,
bool nesting, uint64_t currentBucketStartNs,
uint64_t bucketSizeNs,
- const std::vector<sp<AnomalyTracker>>& anomalyTrackers,
- std::vector<DurationBucket>& bucket)
+ const std::vector<sp<AnomalyTracker>>& anomalyTrackers)
: DurationTracker(key, name, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
- bucketSizeNs, anomalyTrackers, bucket),
+ bucketSizeNs, anomalyTrackers),
mStarted(),
mPaused() {
mLastStartTime = 0;
@@ -128,7 +127,8 @@
mConditionKeyMap.clear();
}
-bool OringDurationTracker::flushIfNeeded(uint64_t eventTime) {
+bool OringDurationTracker::flushIfNeeded(
+ uint64_t eventTime, unordered_map<HashableDimensionKey, vector<DurationBucket>>* output) {
if (eventTime < mCurrentBucketStartTimeNs + mBucketSizeNs) {
return false;
}
@@ -145,7 +145,7 @@
}
if (mDuration > 0) {
current_info.mDuration = mDuration;
- mBucket.push_back(current_info);
+ (*output)[mEventKey].push_back(current_info);
addPastBucketToAnomalyTrackers(current_info.mDuration, current_info.mBucketNum);
VLOG(" duration: %lld", (long long)current_info.mDuration);
}
@@ -157,9 +157,9 @@
info.mBucketEndNs = info.mBucketStartNs + mBucketSizeNs;
info.mBucketNum = mCurrentBucketNum + i;
info.mDuration = mBucketSizeNs;
- mBucket.push_back(info);
- addPastBucketToAnomalyTrackers(info.mDuration, info.mBucketNum);
- VLOG(" add filling bucket with duration %lld", (long long)info.mDuration);
+ (*output)[mEventKey].push_back(info);
+ addPastBucketToAnomalyTrackers(info.mDuration, info.mBucketNum);
+ VLOG(" add filling bucket with duration %lld", (long long)info.mDuration);
}
}
mCurrentBucketStartTimeNs += numBucketsForward * mBucketSizeNs;
@@ -293,12 +293,12 @@
pastNs += currRemainingBucketSizeNs;
// Now deal with the past buckets, starting with the oldest.
- for (int futBucketIdx = 0; futBucketIdx < anomalyTracker.getNumOfPastPackets();
+ for (int futBucketIdx = 0; futBucketIdx < anomalyTracker.getNumOfPastBuckets();
futBucketIdx++) {
// We now overwrite the oldest bucket with the previous 'current', and start a new
// 'current'.
pastNs -= anomalyTracker.getPastBucketValue(
- mEventKey, mCurrentBucketNum - anomalyTracker.getNumOfPastPackets() + futBucketIdx);
+ mEventKey, mCurrentBucketNum - anomalyTracker.getNumOfPastBuckets() + futBucketIdx);
leftNs = thresholdNs - pastNs;
if (leftNs <= mBucketSizeNs) { // Predict anomaly will occur in this bucket.
return eventTimestampNs + currRemainingBucketSizeNs + (futBucketIdx * mBucketSizeNs) +
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index a8404a9..b7d3cba 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -31,8 +31,7 @@
const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard,
int conditionIndex, bool nesting, uint64_t currentBucketStartNs,
uint64_t bucketSizeNs,
- const std::vector<sp<AnomalyTracker>>& anomalyTrackers,
- std::vector<DurationBucket>& bucket);
+ const std::vector<sp<AnomalyTracker>>& anomalyTrackers);
void noteStart(const HashableDimensionKey& key, bool condition, const uint64_t eventTime,
const ConditionKey& conditionKey) override;
@@ -43,7 +42,9 @@
void onSlicedConditionMayChange(const uint64_t timestamp) override;
void onConditionChanged(bool condition, const uint64_t timestamp) override;
- bool flushIfNeeded(uint64_t timestampNs) override;
+ bool flushIfNeeded(
+ uint64_t timestampNs,
+ std::unordered_map<HashableDimensionKey, std::vector<DurationBucket>>* output) override;
int64_t predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
const uint64_t currentTimestamp) const override;
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 1b9efc5..943becb 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#define DEBUG true // STOPSHIP if true
+#include "Log.h"
+
#include "../condition/CombinationConditionTracker.h"
#include "../condition/SimpleConditionTracker.h"
#include "../external/StatsPullerManager.h"
@@ -37,17 +40,17 @@
bool handleMetricWithLogTrackers(const string what, const int metricIndex,
const bool usedForDimension,
- const vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
+ const vector<sp<LogMatchingTracker>>& allAtomMatchers,
const unordered_map<string, int>& logTrackerMap,
unordered_map<int, std::vector<int>>& trackerToMetricMap,
int& logTrackerIndex) {
auto logTrackerIt = logTrackerMap.find(what);
if (logTrackerIt == logTrackerMap.end()) {
- ALOGW("cannot find the LogEntryMatcher \"%s\" in config", what.c_str());
+ ALOGW("cannot find the AtomMatcher \"%s\" in config", what.c_str());
return false;
}
- if (usedForDimension && allLogEntryMatchers[logTrackerIt->second]->getTagIds().size() > 1) {
- ALOGE("LogEntryMatcher \"%s\" has more than one tag ids. When a metric has dimension, "
+ if (usedForDimension && allAtomMatchers[logTrackerIt->second]->getTagIds().size() > 1) {
+ ALOGE("AtomMatcher \"%s\" has more than one tag ids. When a metric has dimension, "
"the \"what\" can only about one atom type.",
what.c_str());
return false;
@@ -61,20 +64,20 @@
bool handleMetricWithConditions(
const string condition, const int metricIndex,
const unordered_map<string, int>& conditionTrackerMap,
- const ::google::protobuf::RepeatedPtrField<::android::os::statsd::EventConditionLink>&
+ const ::google::protobuf::RepeatedPtrField<::android::os::statsd::MetricConditionLink>&
links,
vector<sp<ConditionTracker>>& allConditionTrackers, int& conditionIndex,
unordered_map<int, std::vector<int>>& conditionToMetricMap) {
auto condition_it = conditionTrackerMap.find(condition);
if (condition_it == conditionTrackerMap.end()) {
- ALOGW("cannot find Condition \"%s\" in the config", condition.c_str());
+ ALOGW("cannot find Predicate \"%s\" in the config", condition.c_str());
return false;
}
for (const auto& link : links) {
auto it = conditionTrackerMap.find(link.condition());
if (it == conditionTrackerMap.end()) {
- ALOGW("cannot find Condition \"%s\" in the config", link.condition().c_str());
+ ALOGW("cannot find Predicate \"%s\" in the config", link.condition().c_str());
return false;
}
allConditionTrackers[condition_it->second]->setSliced(true);
@@ -90,23 +93,23 @@
}
bool initLogTrackers(const StatsdConfig& config, unordered_map<string, int>& logTrackerMap,
- vector<sp<LogMatchingTracker>>& allLogEntryMatchers, set<int>& allTagIds) {
- vector<LogEntryMatcher> matcherConfigs;
- const int logEntryMatcherCount = config.log_entry_matcher_size();
- matcherConfigs.reserve(logEntryMatcherCount);
- allLogEntryMatchers.reserve(logEntryMatcherCount);
+ vector<sp<LogMatchingTracker>>& allAtomMatchers, set<int>& allTagIds) {
+ vector<AtomMatcher> matcherConfigs;
+ const int atomMatcherCount = config.atom_matcher_size();
+ matcherConfigs.reserve(atomMatcherCount);
+ allAtomMatchers.reserve(atomMatcherCount);
- for (int i = 0; i < logEntryMatcherCount; i++) {
- const LogEntryMatcher& logMatcher = config.log_entry_matcher(i);
+ for (int i = 0; i < atomMatcherCount; i++) {
+ const AtomMatcher& logMatcher = config.atom_matcher(i);
- int index = allLogEntryMatchers.size();
+ int index = allAtomMatchers.size();
switch (logMatcher.contents_case()) {
- case LogEntryMatcher::ContentsCase::kSimpleLogEntryMatcher:
- allLogEntryMatchers.push_back(new SimpleLogMatchingTracker(
- logMatcher.name(), index, logMatcher.simple_log_entry_matcher()));
+ case AtomMatcher::ContentsCase::kSimpleAtomMatcher:
+ allAtomMatchers.push_back(new SimpleLogMatchingTracker(
+ logMatcher.name(), index, logMatcher.simple_atom_matcher()));
break;
- case LogEntryMatcher::ContentsCase::kCombination:
- allLogEntryMatchers.push_back(
+ case AtomMatcher::ContentsCase::kCombination:
+ allAtomMatchers.push_back(
new CombinationLogMatchingTracker(logMatcher.name(), index));
break;
default:
@@ -115,16 +118,16 @@
// continue;
}
if (logTrackerMap.find(logMatcher.name()) != logTrackerMap.end()) {
- ALOGE("Duplicate LogEntryMatcher found!");
+ ALOGE("Duplicate AtomMatcher found!");
return false;
}
logTrackerMap[logMatcher.name()] = index;
matcherConfigs.push_back(logMatcher);
}
- vector<bool> stackTracker2(allLogEntryMatchers.size(), false);
- for (auto& matcher : allLogEntryMatchers) {
- if (!matcher->init(matcherConfigs, allLogEntryMatchers, logTrackerMap, stackTracker2)) {
+ vector<bool> stackTracker2(allAtomMatchers.size(), false);
+ for (auto& matcher : allAtomMatchers) {
+ if (!matcher->init(matcherConfigs, allAtomMatchers, logTrackerMap, stackTracker2)) {
return false;
}
// Collect all the tag ids that are interesting. TagIds exist in leaf nodes only.
@@ -139,31 +142,31 @@
unordered_map<string, int>& conditionTrackerMap,
vector<sp<ConditionTracker>>& allConditionTrackers,
unordered_map<int, std::vector<int>>& trackerToConditionMap) {
- vector<Condition> conditionConfigs;
- const int conditionTrackerCount = config.condition_size();
+ vector<Predicate> conditionConfigs;
+ const int conditionTrackerCount = config.predicate_size();
conditionConfigs.reserve(conditionTrackerCount);
allConditionTrackers.reserve(conditionTrackerCount);
for (int i = 0; i < conditionTrackerCount; i++) {
- const Condition& condition = config.condition(i);
+ const Predicate& condition = config.predicate(i);
int index = allConditionTrackers.size();
switch (condition.contents_case()) {
- case Condition::ContentsCase::kSimpleCondition: {
+ case Predicate::ContentsCase::kSimplePredicate: {
allConditionTrackers.push_back(new SimpleConditionTracker(
- key, condition.name(), index, condition.simple_condition(), logTrackerMap));
+ key, condition.name(), index, condition.simple_predicate(), logTrackerMap));
break;
}
- case Condition::ContentsCase::kCombination: {
+ case Predicate::ContentsCase::kCombination: {
allConditionTrackers.push_back(
new CombinationConditionTracker(condition.name(), index));
break;
}
default:
- ALOGE("Condition \"%s\" malformed", condition.name().c_str());
+ ALOGE("Predicate \"%s\" malformed", condition.name().c_str());
return false;
}
if (conditionTrackerMap.find(condition.name()) != conditionTrackerMap.end()) {
- ALOGE("Duplicate Condition found!");
+ ALOGE("Duplicate Predicate found!");
return false;
}
conditionTrackerMap[condition.name()] = index;
@@ -188,7 +191,7 @@
bool initMetrics(const ConfigKey& key, const StatsdConfig& config,
const unordered_map<string, int>& logTrackerMap,
const unordered_map<string, int>& conditionTrackerMap,
- const vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
+ const vector<sp<LogMatchingTracker>>& allAtomMatchers,
vector<sp<ConditionTracker>>& allConditionTrackers,
vector<sp<MetricProducer>>& allMetricProducers,
unordered_map<int, std::vector<int>>& conditionToMetricMap,
@@ -214,19 +217,22 @@
metricMap.insert({metric.name(), metricIndex});
int trackerIndex;
if (!handleMetricWithLogTrackers(metric.what(), metricIndex, metric.dimension_size() > 0,
- allLogEntryMatchers, logTrackerMap, trackerToMetricMap,
+ allAtomMatchers, logTrackerMap, trackerToMetricMap,
trackerIndex)) {
return false;
}
int conditionIndex = -1;
if (metric.has_condition()) {
- handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
- metric.links(), allConditionTrackers, conditionIndex,
- conditionToMetricMap);
+ bool good = handleMetricWithConditions(
+ metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
+ allConditionTrackers, conditionIndex, conditionToMetricMap);
+ if (!good) {
+ return false;
+ }
} else {
if (metric.links_size() > 0) {
- ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+ ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
return false;
}
}
@@ -248,53 +254,56 @@
return false;
}
- const Condition& durationWhat = config.condition(what_it->second);
+ const Predicate& durationWhat = config.predicate(what_it->second);
- if (durationWhat.contents_case() != Condition::ContentsCase::kSimpleCondition) {
+ if (durationWhat.contents_case() != Predicate::ContentsCase::kSimplePredicate) {
ALOGE("DurationMetric's \"what\" must be a simple condition");
return false;
}
- const auto& simpleCondition = durationWhat.simple_condition();
+ const auto& simplePredicate = durationWhat.simple_predicate();
- bool nesting = simpleCondition.count_nesting();
+ bool nesting = simplePredicate.count_nesting();
int trackerIndices[3] = {-1, -1, -1};
- if (!simpleCondition.has_start() ||
- !handleMetricWithLogTrackers(simpleCondition.start(), metricIndex,
- metric.dimension_size() > 0, allLogEntryMatchers,
+ if (!simplePredicate.has_start() ||
+ !handleMetricWithLogTrackers(simplePredicate.start(), metricIndex,
+ metric.dimension_size() > 0, allAtomMatchers,
logTrackerMap, trackerToMetricMap, trackerIndices[0])) {
ALOGE("Duration metrics must specify a valid the start event matcher");
return false;
}
- if (simpleCondition.has_stop() &&
- !handleMetricWithLogTrackers(simpleCondition.stop(), metricIndex,
- metric.dimension_size() > 0, allLogEntryMatchers,
+ if (simplePredicate.has_stop() &&
+ !handleMetricWithLogTrackers(simplePredicate.stop(), metricIndex,
+ metric.dimension_size() > 0, allAtomMatchers,
logTrackerMap, trackerToMetricMap, trackerIndices[1])) {
return false;
}
- if (simpleCondition.has_stop_all() &&
- !handleMetricWithLogTrackers(simpleCondition.stop_all(), metricIndex,
- metric.dimension_size() > 0, allLogEntryMatchers,
+ if (simplePredicate.has_stop_all() &&
+ !handleMetricWithLogTrackers(simplePredicate.stop_all(), metricIndex,
+ metric.dimension_size() > 0, allAtomMatchers,
logTrackerMap, trackerToMetricMap, trackerIndices[2])) {
return false;
}
vector<KeyMatcher> internalDimension;
- internalDimension.insert(internalDimension.begin(), simpleCondition.dimension().begin(),
- simpleCondition.dimension().end());
+ internalDimension.insert(internalDimension.begin(), simplePredicate.dimension().begin(),
+ simplePredicate.dimension().end());
int conditionIndex = -1;
if (metric.has_condition()) {
- handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
- metric.links(), allConditionTrackers, conditionIndex,
- conditionToMetricMap);
+ bool good = handleMetricWithConditions(
+ metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
+ allConditionTrackers, conditionIndex, conditionToMetricMap);
+ if (!good) {
+ return false;
+ }
} else {
if (metric.links_size() > 0) {
- ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+ ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
return false;
}
}
@@ -316,19 +325,22 @@
return false;
}
int trackerIndex;
- if (!handleMetricWithLogTrackers(metric.what(), metricIndex, false, allLogEntryMatchers,
+ if (!handleMetricWithLogTrackers(metric.what(), metricIndex, false, allAtomMatchers,
logTrackerMap, trackerToMetricMap, trackerIndex)) {
return false;
}
int conditionIndex = -1;
if (metric.has_condition()) {
- handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
- metric.links(), allConditionTrackers, conditionIndex,
- conditionToMetricMap);
+ bool good = handleMetricWithConditions(
+ metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
+ allConditionTrackers, conditionIndex, conditionToMetricMap);
+ if (!good) {
+ return false;
+ }
} else {
if (metric.links_size() > 0) {
- ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+ ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
return false;
}
}
@@ -351,12 +363,12 @@
metricMap.insert({metric.name(), metricIndex});
int trackerIndex;
if (!handleMetricWithLogTrackers(metric.what(), metricIndex, metric.dimension_size() > 0,
- allLogEntryMatchers, logTrackerMap, trackerToMetricMap,
+ allAtomMatchers, logTrackerMap, trackerToMetricMap,
trackerIndex)) {
return false;
}
- sp<LogMatchingTracker> atomMatcher = allLogEntryMatchers.at(trackerIndex);
+ sp<LogMatchingTracker> atomMatcher = allAtomMatchers.at(trackerIndex);
// If it is pulled atom, it should be simple matcher with one tagId.
int pullTagId = -1;
for (int tagId : atomMatcher->getTagIds()) {
@@ -370,12 +382,15 @@
int conditionIndex = -1;
if (metric.has_condition()) {
- handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
- metric.links(), allConditionTrackers, conditionIndex,
- conditionToMetricMap);
+ bool good = handleMetricWithConditions(
+ metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
+ allConditionTrackers, conditionIndex, conditionToMetricMap);
+ if (!good) {
+ return false;
+ }
} else {
if (metric.links_size() > 0) {
- ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+ ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
return false;
}
}
@@ -397,12 +412,12 @@
metricMap.insert({metric.name(), metricIndex});
int trackerIndex;
if (!handleMetricWithLogTrackers(metric.what(), metricIndex, metric.dimension_size() > 0,
- allLogEntryMatchers, logTrackerMap, trackerToMetricMap,
+ allAtomMatchers, logTrackerMap, trackerToMetricMap,
trackerIndex)) {
return false;
}
- sp<LogMatchingTracker> atomMatcher = allLogEntryMatchers.at(trackerIndex);
+ sp<LogMatchingTracker> atomMatcher = allAtomMatchers.at(trackerIndex);
// If it is pulled atom, it should be simple matcher with one tagId.
int pullTagId = -1;
for (int tagId : atomMatcher->getTagIds()) {
@@ -416,12 +431,15 @@
int conditionIndex = -1;
if (metric.has_condition()) {
- handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
- metric.links(), allConditionTrackers, conditionIndex,
- conditionToMetricMap);
+ bool good = handleMetricWithConditions(
+ metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
+ allConditionTrackers, conditionIndex, conditionToMetricMap);
+ if (!good) {
+ return false;
+ }
} else {
if (metric.links_size() > 0) {
- ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+ ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
return false;
}
}
@@ -444,17 +462,24 @@
alert.metric_name().c_str());
return false;
}
+ if (alert.trigger_if_sum_gt() < 0 || alert.number_of_buckets() <= 0) {
+ ALOGW("invalid alert: threshold=%lld num_buckets= %d",
+ alert.trigger_if_sum_gt(), alert.number_of_buckets());
+ return false;
+ }
const int metricIndex = itr->second;
- sp<AnomalyTracker> anomalyTracker =
- new AnomalyTracker(alert, allMetricProducers[metricIndex]->getBuckeSizeInNs());
- allMetricProducers[metricIndex]->addAnomalyTracker(anomalyTracker);
- allAnomalyTrackers.push_back(anomalyTracker);
+ sp<MetricProducer> metric = allMetricProducers[metricIndex];
+ sp<AnomalyTracker> anomalyTracker = metric->createAnomalyTracker(alert);
+ if (anomalyTracker != nullptr) {
+ metric->addAnomalyTracker(anomalyTracker);
+ allAnomalyTrackers.push_back(anomalyTracker);
+ }
}
return true;
}
bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, set<int>& allTagIds,
- vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
+ vector<sp<LogMatchingTracker>>& allAtomMatchers,
vector<sp<ConditionTracker>>& allConditionTrackers,
vector<sp<MetricProducer>>& allMetricProducers,
vector<sp<AnomalyTracker>>& allAnomalyTrackers,
@@ -465,7 +490,7 @@
unordered_map<string, int> conditionTrackerMap;
unordered_map<string, int> metricProducerMap;
- if (!initLogTrackers(config, logTrackerMap, allLogEntryMatchers, allTagIds)) {
+ if (!initLogTrackers(config, logTrackerMap, allAtomMatchers, allTagIds)) {
ALOGE("initLogMatchingTrackers failed");
return false;
}
@@ -477,7 +502,7 @@
return false;
}
- if (!initMetrics(key, config, logTrackerMap, conditionTrackerMap, allLogEntryMatchers,
+ if (!initMetrics(key, config, logTrackerMap, conditionTrackerMap, allAtomMatchers,
allConditionTrackers, allMetricProducers, conditionToMetricMap,
trackerToMetricMap, metricProducerMap)) {
ALOGE("initMetricProducers failed");
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index e7cbd53..8e9c8e3 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -40,11 +40,11 @@
// [config]: the input StatsdConfig
// output:
// [logTrackerMap]: this map should contain matcher name to index mapping
-// [allLogEntryMatchers]: should store the sp to all the LogMatchingTracker
+// [allAtomMatchers]: should store the sp to all the LogMatchingTracker
// [allTagIds]: contains the set of all interesting tag ids to this config.
bool initLogTrackers(const StatsdConfig& config,
std::unordered_map<std::string, int>& logTrackerMap,
- std::vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
+ std::vector<sp<LogMatchingTracker>>& allAtomMatchers,
std::set<int>& allTagIds);
// Initialize ConditionTrackers
@@ -62,7 +62,7 @@
std::unordered_map<std::string, int>& conditionTrackerMap,
std::vector<sp<ConditionTracker>>& allConditionTrackers,
std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
- std::unordered_map<int, std::vector<EventConditionLink>>& eventConditionLinks);
+ std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks);
// Initialize MetricProducers.
// input:
@@ -79,8 +79,8 @@
const ConfigKey& key, const StatsdConfig& config,
const std::unordered_map<std::string, int>& logTrackerMap,
const std::unordered_map<std::string, int>& conditionTrackerMap,
- const std::unordered_map<int, std::vector<EventConditionLink>>& eventConditionLinks,
- const vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
+ const std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks,
+ const vector<sp<LogMatchingTracker>>& allAtomMatchers,
vector<sp<ConditionTracker>>& allConditionTrackers,
std::vector<sp<MetricProducer>>& allMetricProducers,
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
@@ -89,7 +89,7 @@
// Initialize MetricsManager from StatsdConfig.
// Parameters are the members of MetricsManager. See MetricsManager for declaration.
bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, std::set<int>& allTagIds,
- std::vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
+ std::vector<sp<LogMatchingTracker>>& allAtomMatchers,
std::vector<sp<ConditionTracker>>& allConditionTrackers,
std::vector<sp<MetricProducer>>& allMetricProducers,
vector<sp<AnomalyTracker>>& allAnomalyTrackers,
diff --git a/cmds/statsd/src/packages/PackageInfoListener.h b/cmds/statsd/src/packages/PackageInfoListener.h
index 5aa3db5..bc8b0de 100644
--- a/cmds/statsd/src/packages/PackageInfoListener.h
+++ b/cmds/statsd/src/packages/PackageInfoListener.h
@@ -28,7 +28,7 @@
public:
// Uid map will notify this listener that the app with apk name and uid has been upgraded to
// the specified version.
- virtual void notifyAppUpgrade(const std::string& apk, const int uid, const int version) = 0;
+ virtual void notifyAppUpgrade(const std::string& apk, const int uid, const int64_t version) = 0;
// Notify interested listeners that the given apk and uid combination no longer exits.
virtual void notifyAppRemoved(const std::string& apk, const int uid) = 0;
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 6c32d3e..6e7a613 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -13,19 +13,29 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+#define DEBUG true // STOPSHIP if true
#include "Log.h"
+#include "guardrail/StatsdStats.h"
#include "packages/UidMap.h"
+#include <android/os/IStatsCompanionService.h>
+#include <binder/IServiceManager.h>
#include <utils/Errors.h>
+#include <inttypes.h>
+
using namespace android;
namespace android {
namespace os {
namespace statsd {
+UidMap::UidMap() : mBytesUsed(0) {
+}
+UidMap::~UidMap() {
+}
+
bool UidMap::hasApp(int uid, const string& packageName) const {
lock_guard<mutex> lock(mMutex);
@@ -38,7 +48,7 @@
return false;
}
-int UidMap::getAppVersion(int uid, const string& packageName) const {
+int64_t UidMap::getAppVersion(int uid, const string& packageName) const {
lock_guard<mutex> lock(mMutex);
auto range = mMap.equal_range(uid);
@@ -50,13 +60,13 @@
return 0;
}
-void UidMap::updateMap(const vector<int32_t>& uid, const vector<int32_t>& versionCode,
+void UidMap::updateMap(const vector<int32_t>& uid, const vector<int64_t>& versionCode,
const vector<String16>& packageName) {
updateMap(time(nullptr) * NS_PER_SEC, uid, versionCode, packageName);
}
void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
- const vector<int32_t>& versionCode, const vector<String16>& packageName) {
+ const vector<int64_t>& versionCode, const vector<String16>& packageName) {
lock_guard<mutex> lock(mMutex); // Exclusively lock for updates.
mMap.clear();
@@ -73,14 +83,18 @@
t->set_version(int(versionCode[j]));
t->set_uid(uid[j]);
}
+ mBytesUsed += snapshot->ByteSize();
+ StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
+ StatsdStats::getInstance().setUidMapSnapshots(mOutput.snapshots_size());
+ ensureBytesUsedBelowLimit();
}
-void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int32_t& versionCode) {
+void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int64_t& versionCode) {
updateApp(time(nullptr) * NS_PER_SEC, app_16, uid, versionCode);
}
void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const int32_t& uid,
- const int32_t& versionCode) {
+ const int64_t& versionCode) {
lock_guard<mutex> lock(mMutex);
string app = string(String8(app_16).string());
@@ -96,19 +110,45 @@
log->set_app(app);
log->set_uid(uid);
log->set_version(versionCode);
+ mBytesUsed += log->ByteSize();
+ StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
+ StatsdStats::getInstance().setUidMapChanges(mOutput.changes_size());
+ ensureBytesUsedBelowLimit();
auto range = mMap.equal_range(int(uid));
for (auto it = range.first; it != range.second; ++it) {
if (it->second.packageName == app) {
- it->second.versionCode = int(versionCode);
+ it->second.versionCode = versionCode;
return;
}
- ALOGD("updateApp failed to find the app %s with uid %i to update", app.c_str(), uid);
+ VLOG("updateApp failed to find the app %s with uid %i to update", app.c_str(), uid);
return;
}
// Otherwise, we need to add an app at this uid.
- mMap.insert(make_pair(uid, AppData(app, int(versionCode))));
+ mMap.insert(make_pair(uid, AppData(app, versionCode)));
+}
+
+void UidMap::ensureBytesUsedBelowLimit() {
+ size_t limit;
+ if (maxBytesOverride <= 0) {
+ limit = StatsdStats::kMaxBytesUsedUidMap;
+ } else {
+ limit = maxBytesOverride;
+ }
+ while (mBytesUsed > limit) {
+ VLOG("Bytes used %zu is above limit %zu, need to delete something", mBytesUsed, limit);
+ if (mOutput.snapshots_size() > 0) {
+ auto snapshots = mOutput.mutable_snapshots();
+ snapshots->erase(snapshots->begin()); // Remove first snapshot.
+ StatsdStats::getInstance().noteUidMapDropped(1, 0);
+ } else if (mOutput.changes_size() > 0) {
+ auto changes = mOutput.mutable_changes();
+ changes->DeleteSubrange(0, 1);
+ StatsdStats::getInstance().noteUidMapDropped(0, 1);
+ }
+ mBytesUsed = mOutput.ByteSize();
+ }
}
void UidMap::removeApp(const String16& app_16, const int32_t& uid) {
@@ -128,6 +168,10 @@
log->set_timestamp_nanos(timestamp);
log->set_app(app);
log->set_uid(uid);
+ mBytesUsed += log->ByteSize();
+ StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
+ StatsdStats::getInstance().setUidMapChanges(mOutput.changes_size());
+ ensureBytesUsedBelowLimit();
auto range = mMap.equal_range(int(uid));
for (auto it = range.first; it != range.second; ++it) {
@@ -136,7 +180,7 @@
return;
}
}
- ALOGD("removeApp failed to find the app %s with uid %i to remove", app.c_str(), uid);
+ VLOG("removeApp failed to find the app %s with uid %i to remove", app.c_str(), uid);
return;
}
@@ -177,7 +221,6 @@
void UidMap::clearOutput() {
mOutput.Clear();
-
// Re-initialize the initial state for the outputs. This results in extra data being uploaded
// but helps ensure we can re-construct the UID->app name, versionCode mapping in server.
auto snapshot = mOutput.add_snapshots();
@@ -187,6 +230,12 @@
t->set_version(it.second.versionCode);
t->set_uid(it.first);
}
+
+ // Also update the guardrail trackers.
+ StatsdStats::getInstance().setUidMapChanges(0);
+ StatsdStats::getInstance().setUidMapSnapshots(1);
+ mBytesUsed = snapshot->ByteSize();
+ StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
}
int64_t UidMap::getMinimumTimestampNs() {
@@ -201,6 +250,10 @@
return m;
}
+size_t UidMap::getBytesUsed() {
+ return mBytesUsed;
+}
+
UidMapping UidMap::getOutput(const ConfigKey& key) {
return getOutput(time(nullptr) * NS_PER_SEC, key);
}
@@ -236,6 +289,10 @@
}
}
}
+ mBytesUsed = mOutput.ByteSize(); // Compute actual size after potential deletions.
+ StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
+ StatsdStats::getInstance().setUidMapChanges(mOutput.changes_size());
+ StatsdStats::getInstance().setUidMapSnapshots(mOutput.snapshots_size());
return ret;
}
@@ -243,13 +300,30 @@
lock_guard<mutex> lock(mMutex);
for (auto it : mMap) {
- fprintf(out, "%s, v%d (%i)\n", it.second.packageName.c_str(), it.second.versionCode,
- it.first);
+ fprintf(out, "%s, v%" PRId64 " (%i)\n", it.second.packageName.c_str(),
+ it.second.versionCode, it.first);
}
}
void UidMap::OnConfigUpdated(const ConfigKey& key) {
mLastUpdatePerConfigKey[key] = -1;
+
+ // Ensure there is at least one snapshot available since this configuration also needs to know
+ // what all the uid's represent.
+ if (mOutput.snapshots_size() == 0) {
+ sp<IStatsCompanionService> statsCompanion = nullptr;
+ // Get statscompanion service from service manager
+ const sp<IServiceManager> sm(defaultServiceManager());
+ if (sm != nullptr) {
+ const String16 name("statscompanion");
+ statsCompanion = interface_cast<IStatsCompanionService>(sm->checkService(name));
+ if (statsCompanion == nullptr) {
+ ALOGW("statscompanion service unavailable!");
+ return;
+ }
+ statsCompanion->triggerUidSnapshot();
+ }
+ }
}
void UidMap::OnConfigRemoved(const ConfigKey& key) {
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 24eb966..9e1ad69 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -41,31 +41,32 @@
struct AppData {
const string packageName;
- int versionCode;
+ int64_t versionCode;
- AppData(const string& a, const int v) : packageName(a), versionCode(v){};
+ AppData(const string& a, const int64_t v) : packageName(a), versionCode(v){};
};
// UidMap keeps track of what the corresponding app name (APK name) and version code for every uid
// at any given moment. This map must be updated by StatsCompanionService.
class UidMap : public virtual android::RefBase {
public:
+ UidMap();
+ ~UidMap();
+
/*
* All three inputs must be the same size, and the jth element in each array refers to the same
* tuple, ie. uid[j] corresponds to packageName[j] with versionCode[j].
*/
- // TODO: Add safeguards to call clearOutput if there's too much data already stored.
- void updateMap(const vector<int32_t>& uid, const vector<int32_t>& versionCode,
+ void updateMap(const vector<int32_t>& uid, const vector<int64_t>& versionCode,
const vector<String16>& packageName);
- // TODO: Add safeguards to call clearOutput if there's too much data already stored.
- void updateApp(const String16& packageName, const int32_t& uid, const int32_t& versionCode);
+ void updateApp(const String16& packageName, const int32_t& uid, const int64_t& versionCode);
void removeApp(const String16& packageName, const int32_t& uid);
// Returns true if the given uid contains the specified app (eg. com.google.android.gms).
bool hasApp(int uid, const string& packageName) const;
- int getAppVersion(int uid, const string& packageName) const;
+ int64_t getAppVersion(int uid, const string& packageName) const;
// Helper for debugging contents of this uid map. Can be triggered with:
// adb shell cmd stats print-uid-map
@@ -98,13 +99,15 @@
// in case we lose a previous upload.
void clearOutput();
+ // Get currently cached value of memory used by UID map.
+ size_t getBytesUsed();
+
private:
void updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
- const vector<int32_t>& versionCode, const vector<String16>& packageName);
+ const vector<int64_t>& versionCode, const vector<String16>& packageName);
- // TODO: Add safeguards to call clearOutput if there's too much data already stored.
void updateApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid,
- const int32_t& versionCode);
+ const int64_t& versionCode);
void removeApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid);
UidMapping getOutput(const int64_t& timestamp, const ConfigKey& key);
@@ -135,8 +138,22 @@
// Returns the minimum value from mConfigKeys.
int64_t getMinimumTimestampNs();
+ // If our current used bytes is above the limit, then we clear out the earliest snapshot. If
+ // there are no more snapshots, then we clear out the earliest delta. We repeat the deletions
+ // until the memory consumed by mOutput is below the specified limit.
+ void ensureBytesUsedBelowLimit();
+
+ // Override used for testing the max memory allowed by uid map. -1 means we use the value
+ // specified in StatsdStats.h with the rest of the guardrails.
+ size_t maxBytesOverride = -1;
+
+ // Cache the size of mOutput;
+ size_t mBytesUsed;
+
// Allows unit-test to access private methods.
FRIEND_TEST(UidMapTest, TestClearingOutput);
+ FRIEND_TEST(UidMapTest, TestMemoryComputed);
+ FRIEND_TEST(UidMapTest, TestMemoryGuardrail);
};
} // namespace statsd
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 81f8eb6..f8b91fe 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -102,7 +102,7 @@
message PackageInfo {
optional string name = 1;
- optional int32 version = 2;
+ optional int64 version = 2;
optional int32 uid = 3;
}
@@ -119,7 +119,7 @@
optional string app = 3;
optional int32 uid = 4;
- optional int32 version = 5;
+ optional int64 version = 5;
}
repeated Change changes = 2;
}
@@ -193,6 +193,11 @@
optional int32 max_tuple_counts = 2;
}
+ message AlertStats {
+ optional string name = 1;
+ optional int32 declared_times = 2;
+ }
+
message ConfigStats {
optional int32 uid = 1;
optional string name = 2;
@@ -206,9 +211,11 @@
repeated int32 broadcast_sent_time_sec = 10;
repeated int32 data_drop_time_sec = 11;
- repeated MatcherStats matcher_stats = 12;
- repeated ConditionStats condition_stats = 13;
- repeated MetricStats metric_stats = 14;
+ repeated int32 dump_report_time_sec = 12;
+ repeated MatcherStats matcher_stats = 13;
+ repeated ConditionStats condition_stats = 14;
+ repeated MetricStats metric_stats = 15;
+ repeated AlertStats alert_stats = 16;
}
repeated ConfigStats config_stats = 3;
@@ -219,4 +226,18 @@
}
repeated AtomStats atom_stats = 7;
+
+ message UidMapStats {
+ optional int32 snapshots = 1;
+ optional int32 changes = 2;
+ optional int32 bytes_used = 3;
+ optional int32 dropped_snapshots = 4;
+ optional int32 dropped_changes = 5;
+ }
+ optional UidMapStats uidmap_stats = 8;
+
+ message AnomalyAlarmStats {
+ optional int32 alarms_registered = 1;
+ }
+ optional AnomalyAlarmStats anomaly_alarm_stats = 9;
}
\ No newline at end of file
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index c8fa155..c9654af 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -23,99 +23,99 @@
option java_outer_classname = "StatsdConfigProto";
message KeyMatcher {
- optional int32 key = 1;
+ optional int32 key = 1;
- optional bool as_package_name = 2 [ default = false ];
+ optional bool as_package_name = 2 [default = false];
}
message KeyValueMatcher {
- optional KeyMatcher key_matcher = 1;
+ optional KeyMatcher key_matcher = 1;
- oneof value_matcher {
- bool eq_bool = 2;
- string eq_string = 3;
- int32 eq_int = 4;
+ oneof value_matcher {
+ bool eq_bool = 2;
+ string eq_string = 3;
+ int32 eq_int = 4;
- int64 lt_int = 5;
- int64 gt_int = 6;
- float lt_float = 7;
- float gt_float = 8;
+ int64 lt_int = 5;
+ int64 gt_int = 6;
+ float lt_float = 7;
+ float gt_float = 8;
- int64 lte_int = 9;
- int64 gte_int = 10;
- }
+ int64 lte_int = 9;
+ int64 gte_int = 10;
+ }
}
enum LogicalOperation {
- LOGICAL_OPERATION_UNSPECIFIED = 0;
- AND = 1;
- OR = 2;
- NOT = 3;
- NAND = 4;
- NOR = 5;
+ LOGICAL_OPERATION_UNSPECIFIED = 0;
+ AND = 1;
+ OR = 2;
+ NOT = 3;
+ NAND = 4;
+ NOR = 5;
}
-message SimpleLogEntryMatcher {
- optional int32 tag = 1;
+message SimpleAtomMatcher {
+ optional int32 tag = 1;
- repeated KeyValueMatcher key_value_matcher = 2;
+ repeated KeyValueMatcher key_value_matcher = 2;
}
-message LogEntryMatcher {
- optional string name = 1;
+message AtomMatcher {
+ optional string name = 1;
- message Combination {
- optional LogicalOperation operation = 1;
+ message Combination {
+ optional LogicalOperation operation = 1;
- repeated string matcher = 2;
- }
- oneof contents {
- SimpleLogEntryMatcher simple_log_entry_matcher = 2;
- Combination combination = 3;
- }
+ repeated string matcher = 2;
+ }
+ oneof contents {
+ SimpleAtomMatcher simple_atom_matcher = 2;
+ Combination combination = 3;
+ }
}
-message SimpleCondition {
- optional string start = 1;
+message SimplePredicate {
+ optional string start = 1;
- optional string stop = 2;
+ optional string stop = 2;
- optional bool count_nesting = 3 [default = true];
+ optional bool count_nesting = 3 [default = true];
- optional string stop_all = 4;
+ optional string stop_all = 4;
- enum InitialValue {
- UNKNOWN = 0;
- FALSE = 1;
- }
- optional InitialValue initial_value = 5 [default = FALSE];
+ enum InitialValue {
+ UNKNOWN = 0;
+ FALSE = 1;
+ }
+ optional InitialValue initial_value = 5 [default = FALSE];
- repeated KeyMatcher dimension = 6;
+ repeated KeyMatcher dimension = 6;
}
-message Condition {
- optional string name = 1;
+message Predicate {
+ optional string name = 1;
- message Combination {
- optional LogicalOperation operation = 1;
+ message Combination {
+ optional LogicalOperation operation = 1;
- repeated string condition = 2;
- }
+ repeated string predicate = 2;
+ }
- oneof contents {
- SimpleCondition simple_condition = 2;
- Combination combination = 3;
- }
+ oneof contents {
+ SimplePredicate simple_predicate = 2;
+ Combination combination = 3;
+ }
}
message Bucket {
- optional int64 bucket_size_millis = 1;
+ optional int64 bucket_size_millis = 1;
}
-message EventConditionLink {
+message MetricConditionLink {
optional string condition = 1;
- repeated KeyMatcher key_in_main = 2;
+ repeated KeyMatcher key_in_what = 2;
repeated KeyMatcher key_in_condition = 3;
}
@@ -127,7 +127,7 @@
optional string condition = 3;
- repeated EventConditionLink links = 4;
+ repeated MetricConditionLink links = 4;
}
message CountMetric {
@@ -141,7 +141,7 @@
optional Bucket bucket = 5;
- repeated EventConditionLink links = 6;
+ repeated MetricConditionLink links = 6;
}
message DurationMetric {
@@ -151,12 +151,12 @@
optional string condition = 3;
- repeated EventConditionLink links = 4;
+ repeated MetricConditionLink links = 4;
enum AggregationType {
- SUM = 1;
+ SUM = 1;
- MAX_SPARSE = 2;
+ MAX_SPARSE = 2;
}
optional AggregationType aggregation_type = 5 [default = SUM];
@@ -178,7 +178,7 @@
optional Bucket bucket = 6;
- repeated EventConditionLink links = 7;
+ repeated MetricConditionLink links = 7;
}
message ValueMetric {
@@ -194,11 +194,9 @@
optional Bucket bucket = 6;
- repeated EventConditionLink links = 7;
+ repeated MetricConditionLink links = 7;
- enum AggregationType {
- SUM = 1;
- }
+ enum AggregationType { SUM = 1; }
optional AggregationType aggregation_type = 8 [default = SUM];
}
@@ -208,7 +206,7 @@
optional string metric_name = 2;
message IncidentdDetails {
- repeated int32 section = 1;
+ repeated int32 section = 1;
}
optional IncidentdDetails incidentd_details = 3;
@@ -232,9 +230,9 @@
repeated DurationMetric duration_metric = 6;
- repeated LogEntryMatcher log_entry_matcher = 7;
+ repeated AtomMatcher atom_matcher = 7;
- repeated Condition condition = 8;
+ repeated Predicate predicate = 8;
repeated Alert alert = 9;
}
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index a95e899..62f06a7 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -40,7 +40,7 @@
void StorageManager::writeFile(const char* file, const void* buffer, int numBytes) {
int fd = open(file, O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
- if (fd != -1) {
+ if (fd == -1) {
VLOG("Attempt to access %s but failed", file);
return;
}
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index 40c0e9d..1ec9155 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -36,10 +36,10 @@
extern "C" void android_log_rewind(android_log_context ctx);
#ifdef __ANDROID__
-TEST(LogEntryMatcherTest, TestSimpleMatcher) {
+TEST(AtomMatcherTest, TestSimpleMatcher) {
// Set up the matcher
- LogEntryMatcher matcher;
- auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
simpleMatcher->set_tag(TAG_ID);
LogEvent event(TAG_ID, 0);
@@ -49,10 +49,10 @@
EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
}
-TEST(LogEntryMatcherTest, TestBoolMatcher) {
+TEST(AtomMatcherTest, TestBoolMatcher) {
// Set up the matcher
- LogEntryMatcher matcher;
- auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
simpleMatcher->set_tag(TAG_ID);
auto keyValue1 = simpleMatcher->add_key_value_matcher();
keyValue1->mutable_key_matcher()->set_key(FIELD_ID_1);
@@ -84,10 +84,10 @@
EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
}
-TEST(LogEntryMatcherTest, TestStringMatcher) {
+TEST(AtomMatcherTest, TestStringMatcher) {
// Set up the matcher
- LogEntryMatcher matcher;
- auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
simpleMatcher->set_tag(TAG_ID);
auto keyValue = simpleMatcher->add_key_value_matcher();
keyValue->mutable_key_matcher()->set_key(FIELD_ID_1);
@@ -103,10 +103,10 @@
EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
}
-TEST(LogEntryMatcherTest, TestMultiFieldsMatcher) {
+TEST(AtomMatcherTest, TestMultiFieldsMatcher) {
// Set up the matcher
- LogEntryMatcher matcher;
- auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
simpleMatcher->set_tag(TAG_ID);
auto keyValue1 = simpleMatcher->add_key_value_matcher();
keyValue1->mutable_key_matcher()->set_key(FIELD_ID_1);
@@ -135,10 +135,10 @@
EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
}
-TEST(LogEntryMatcherTest, TestIntComparisonMatcher) {
+TEST(AtomMatcherTest, TestIntComparisonMatcher) {
// Set up the matcher
- LogEntryMatcher matcher;
- auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
simpleMatcher->set_tag(TAG_ID);
auto keyValue = simpleMatcher->add_key_value_matcher();
@@ -192,10 +192,10 @@
EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
}
-TEST(LogEntryMatcherTest, TestFloatComparisonMatcher) {
+TEST(AtomMatcherTest, TestFloatComparisonMatcher) {
// Set up the matcher
- LogEntryMatcher matcher;
- auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
simpleMatcher->set_tag(TAG_ID);
auto keyValue = simpleMatcher->add_key_value_matcher();
@@ -225,14 +225,14 @@
}
// Helper for the composite matchers.
-void addSimpleMatcher(SimpleLogEntryMatcher* simpleMatcher, int tag, int key, int val) {
+void addSimpleMatcher(SimpleAtomMatcher* simpleMatcher, int tag, int key, int val) {
simpleMatcher->set_tag(tag);
auto keyValue = simpleMatcher->add_key_value_matcher();
keyValue->mutable_key_matcher()->set_key(key);
keyValue->set_eq_int(val);
}
-TEST(LogEntryMatcherTest, TestAndMatcher) {
+TEST(AtomMatcherTest, TestAndMatcher) {
// Set up the matcher
LogicalOperation operation = LogicalOperation::AND;
@@ -256,7 +256,7 @@
EXPECT_TRUE(combinationMatch(children, operation, matcherResults));
}
-TEST(LogEntryMatcherTest, TestOrMatcher) {
+TEST(AtomMatcherTest, TestOrMatcher) {
// Set up the matcher
LogicalOperation operation = LogicalOperation::OR;
@@ -280,7 +280,7 @@
EXPECT_FALSE(combinationMatch(children, operation, matcherResults));
}
-TEST(LogEntryMatcherTest, TestNotMatcher) {
+TEST(AtomMatcherTest, TestNotMatcher) {
// Set up the matcher
LogicalOperation operation = LogicalOperation::NOT;
@@ -297,7 +297,7 @@
EXPECT_TRUE(combinationMatch(children, operation, matcherResults));
}
-TEST(LogEntryMatcherTest, TestNandMatcher) {
+TEST(AtomMatcherTest, TestNandMatcher) {
// Set up the matcher
LogicalOperation operation = LogicalOperation::NAND;
@@ -322,7 +322,7 @@
EXPECT_FALSE(combinationMatch(children, operation, matcherResults));
}
-TEST(LogEntryMatcherTest, TestNorMatcher) {
+TEST(AtomMatcherTest, TestNorMatcher) {
// Set up the matcher
LogicalOperation operation = LogicalOperation::NOR;
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 2adec94..c6a5310 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -34,7 +34,7 @@
using std::set;
using std::unordered_map;
using std::vector;
-using android::os::statsd::Condition;
+using android::os::statsd::Predicate;
#ifdef __ANDROID__
@@ -46,30 +46,30 @@
StatsdConfig config;
config.set_name("12345");
- LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+ AtomMatcher* eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("SCREEN_IS_ON");
- SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->set_tag(2 /*SCREEN_STATE_CHANGE*/);
- simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
+ SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_tag(2 /*SCREEN_STATE_CHANGE*/);
+ simpleAtomMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
- simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
+ simpleAtomMatcher->mutable_key_value_matcher(0)->set_eq_int(
2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
- eventMatcher = config.add_log_entry_matcher();
+ eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("SCREEN_IS_OFF");
- simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->set_tag(2 /*SCREEN_STATE_CHANGE*/);
- simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
+ simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_tag(2 /*SCREEN_STATE_CHANGE*/);
+ simpleAtomMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
- simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
+ simpleAtomMatcher->mutable_key_value_matcher(0)->set_eq_int(
1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
- eventMatcher = config.add_log_entry_matcher();
+ eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("SCREEN_ON_OR_OFF");
- LogEntryMatcher_Combination* combination = eventMatcher->mutable_combination();
+ AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
combination->set_operation(LogicalOperation::OR);
combination->add_matcher("SCREEN_IS_ON");
combination->add_matcher("SCREEN_IS_OFF");
@@ -94,20 +94,20 @@
StatsdConfig config;
config.set_name("12345");
- LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+ AtomMatcher* eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("SCREEN_IS_ON");
- SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->set_tag(2 /*SCREEN_STATE_CHANGE*/);
- simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
+ SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_tag(2 /*SCREEN_STATE_CHANGE*/);
+ simpleAtomMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
- simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
+ simpleAtomMatcher->mutable_key_value_matcher(0)->set_eq_int(
2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
- eventMatcher = config.add_log_entry_matcher();
+ eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("SCREEN_ON_OR_OFF");
- LogEntryMatcher_Combination* combination = eventMatcher->mutable_combination();
+ AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
combination->set_operation(LogicalOperation::OR);
combination->add_matcher("SCREEN_IS_ON");
// Circle dependency
@@ -120,7 +120,7 @@
StatsdConfig config;
config.set_name("12345");
- LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+ AtomMatcher* eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("SCREEN_IS_ON");
CountMetric* metric = config.add_count_metric();
@@ -143,20 +143,20 @@
StatsdConfig config;
config.set_name("12345");
- LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+ AtomMatcher* eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("SCREEN_IS_ON");
- SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->set_tag(2 /*SCREEN_STATE_CHANGE*/);
- simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
+ SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_tag(2 /*SCREEN_STATE_CHANGE*/);
+ simpleAtomMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
- simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
+ simpleAtomMatcher->mutable_key_value_matcher(0)->set_eq_int(
2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
- eventMatcher = config.add_log_entry_matcher();
+ eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("SCREEN_ON_OR_OFF");
- LogEntryMatcher_Combination* combination = eventMatcher->mutable_combination();
+ AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
combination->set_operation(LogicalOperation::OR);
combination->add_matcher("SCREEN_IS_ON");
// undefined matcher
@@ -165,24 +165,43 @@
return config;
}
+StatsdConfig buildMissingPredicate() {
+ StatsdConfig config;
+ config.set_name("12345");
+
+ CountMetric* metric = config.add_count_metric();
+ metric->set_name("3");
+ metric->set_what("SCREEN_EVENT");
+ metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
+ metric->set_condition("SOME_CONDITION");
+
+ AtomMatcher* eventMatcher = config.add_atom_matcher();
+ eventMatcher->set_name("SCREEN_EVENT");
+
+ SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_tag(2);
+
+ return config;
+}
+
StatsdConfig buildDimensionMetricsWithMultiTags() {
StatsdConfig config;
config.set_name("12345");
- LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+ AtomMatcher* eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("BATTERY_VERY_LOW");
- SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->set_tag(2);
+ SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_tag(2);
- eventMatcher = config.add_log_entry_matcher();
+ eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("BATTERY_VERY_VERY_LOW");
- simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->set_tag(3);
+ simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_tag(3);
- eventMatcher = config.add_log_entry_matcher();
+ eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("BATTERY_LOW");
- LogEntryMatcher_Combination* combination = eventMatcher->mutable_combination();
+ AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
combination->set_operation(LogicalOperation::OR);
combination->add_matcher("BATTERY_VERY_LOW");
combination->add_matcher("BATTERY_VERY_VERY_LOW");
@@ -204,43 +223,43 @@
return config;
}
-StatsdConfig buildCircleConditions() {
+StatsdConfig buildCirclePredicates() {
StatsdConfig config;
config.set_name("12345");
- LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+ AtomMatcher* eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("SCREEN_IS_ON");
- SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->set_tag(2 /*SCREEN_STATE_CHANGE*/);
- simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
+ SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_tag(2 /*SCREEN_STATE_CHANGE*/);
+ simpleAtomMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
- simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
+ simpleAtomMatcher->mutable_key_value_matcher(0)->set_eq_int(
2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
- eventMatcher = config.add_log_entry_matcher();
+ eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("SCREEN_IS_OFF");
- simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->set_tag(2 /*SCREEN_STATE_CHANGE*/);
- simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
+ simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_tag(2 /*SCREEN_STATE_CHANGE*/);
+ simpleAtomMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
- simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
+ simpleAtomMatcher->mutable_key_value_matcher(0)->set_eq_int(
1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
- auto condition = config.add_condition();
+ auto condition = config.add_predicate();
condition->set_name("SCREEN_IS_ON");
- SimpleCondition* simpleCondition = condition->mutable_simple_condition();
- simpleCondition->set_start("SCREEN_IS_ON");
- simpleCondition->set_stop("SCREEN_IS_OFF");
+ SimplePredicate* simplePredicate = condition->mutable_simple_predicate();
+ simplePredicate->set_start("SCREEN_IS_ON");
+ simplePredicate->set_stop("SCREEN_IS_OFF");
- condition = config.add_condition();
+ condition = config.add_predicate();
condition->set_name("SCREEN_IS_EITHER_ON_OFF");
- Condition_Combination* combination = condition->mutable_combination();
+ Predicate_Combination* combination = condition->mutable_combination();
combination->set_operation(LogicalOperation::OR);
- combination->add_condition("SCREEN_IS_ON");
- combination->add_condition("SCREEN_IS_EITHER_ON_OFF");
+ combination->add_predicate("SCREEN_IS_ON");
+ combination->add_predicate("SCREEN_IS_EITHER_ON_OFF");
return config;
}
@@ -248,7 +267,7 @@
TEST(MetricsManagerTest, TestGoodConfig) {
StatsdConfig config = buildGoodConfig();
set<int> allTagIds;
- vector<sp<LogMatchingTracker>> allLogEntryMatchers;
+ vector<sp<LogMatchingTracker>> allAtomMatchers;
vector<sp<ConditionTracker>> allConditionTrackers;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
@@ -256,7 +275,7 @@
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
- EXPECT_TRUE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers,
+ EXPECT_TRUE(initStatsdConfig(kConfigKey, config, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
EXPECT_EQ(1u, allMetricProducers.size());
@@ -266,7 +285,7 @@
TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
StatsdConfig config = buildDimensionMetricsWithMultiTags();
set<int> allTagIds;
- vector<sp<LogMatchingTracker>> allLogEntryMatchers;
+ vector<sp<LogMatchingTracker>> allAtomMatchers;
vector<sp<ConditionTracker>> allConditionTrackers;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
@@ -274,7 +293,7 @@
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
- EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers,
+ EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
}
@@ -282,7 +301,7 @@
TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
StatsdConfig config = buildCircleMatchers();
set<int> allTagIds;
- vector<sp<LogMatchingTracker>> allLogEntryMatchers;
+ vector<sp<LogMatchingTracker>> allAtomMatchers;
vector<sp<ConditionTracker>> allConditionTrackers;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
@@ -290,7 +309,7 @@
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
- EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers,
+ EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
}
@@ -298,22 +317,37 @@
TEST(MetricsManagerTest, TestMissingMatchers) {
StatsdConfig config = buildMissingMatchers();
set<int> allTagIds;
- vector<sp<LogMatchingTracker>> allLogEntryMatchers;
+ vector<sp<LogMatchingTracker>> allAtomMatchers;
vector<sp<ConditionTracker>> allConditionTrackers;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
- EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers,
+ EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
}
-TEST(MetricsManagerTest, TestCircleConditionDependency) {
- StatsdConfig config = buildCircleConditions();
+TEST(MetricsManagerTest, TestMissingPredicate) {
+ StatsdConfig config = buildMissingPredicate();
set<int> allTagIds;
- vector<sp<LogMatchingTracker>> allLogEntryMatchers;
+ vector<sp<LogMatchingTracker>> allAtomMatchers;
+ vector<sp<ConditionTracker>> allConditionTrackers;
+ vector<sp<MetricProducer>> allMetricProducers;
+ std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
+ unordered_map<int, std::vector<int>> conditionToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToConditionMap;
+ EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allAtomMatchers,
+ allConditionTrackers, allMetricProducers, allAnomalyTrackers,
+ conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
+}
+
+TEST(MetricsManagerTest, TestCirclePredicateDependency) {
+ StatsdConfig config = buildCirclePredicates();
+ set<int> allTagIds;
+ vector<sp<LogMatchingTracker>> allAtomMatchers;
vector<sp<ConditionTracker>> allConditionTrackers;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
@@ -321,7 +355,7 @@
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
- EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers,
+ EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
}
@@ -329,7 +363,7 @@
TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
StatsdConfig config = buildAlertWithUnknownMetric();
set<int> allTagIds;
- vector<sp<LogMatchingTracker>> allLogEntryMatchers;
+ vector<sp<LogMatchingTracker>> allAtomMatchers;
vector<sp<ConditionTracker>> allConditionTrackers;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
@@ -337,7 +371,7 @@
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
- EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers,
+ EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
}
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
new file mode 100644
index 0000000..ff04d95
--- /dev/null
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -0,0 +1,117 @@
+// 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.
+
+#include "StatsLogProcessor.h"
+#include "config/ConfigKey.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "guardrail/StatsdStats.h"
+#include "logd/LogEvent.h"
+#include "packages/UidMap.h"
+#include "statslog.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <stdio.h>
+
+using namespace android;
+using namespace testing;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#ifdef __ANDROID__
+
+/**
+ * Mock MetricsManager (ByteSize() is called).
+ */
+class MockMetricsManager : public MetricsManager {
+public:
+ MockMetricsManager() : MetricsManager(ConfigKey(1, "key"), StatsdConfig()) {
+ }
+
+ MOCK_METHOD0(byteSize, size_t());
+ MOCK_METHOD0(onDumpReport, std::vector<std::unique_ptr<std::vector<uint8_t>>>());
+};
+
+TEST(StatsLogProcessorTest, TestRateLimitByteSize) {
+ sp<UidMap> m = new UidMap();
+ sp<AnomalyMonitor> anomalyMonitor;
+ // Construct the processor with a dummy sendBroadcast function that does nothing.
+ StatsLogProcessor p(m, anomalyMonitor, [](const ConfigKey& key) {});
+
+ MockMetricsManager mockMetricsManager;
+
+ ConfigKey key(100, "key");
+ // Expect only the first flush to trigger a check for byte size since the last two are
+ // rate-limited.
+ EXPECT_CALL(mockMetricsManager, byteSize()).Times(1);
+ p.flushIfNecessary(99, key, mockMetricsManager);
+ p.flushIfNecessary(100, key, mockMetricsManager);
+ p.flushIfNecessary(101, key, mockMetricsManager);
+}
+
+TEST(StatsLogProcessorTest, TestRateLimitBroadcast) {
+ sp<UidMap> m = new UidMap();
+ sp<AnomalyMonitor> anomalyMonitor;
+ int broadcastCount = 0;
+ StatsLogProcessor p(m, anomalyMonitor,
+ [&broadcastCount](const ConfigKey& key) { broadcastCount++; });
+
+ MockMetricsManager mockMetricsManager;
+
+ ConfigKey key(100, "key");
+ EXPECT_CALL(mockMetricsManager, byteSize())
+ .Times(2)
+ .WillRepeatedly(Return(int(StatsdStats::kMaxMetricsBytesPerConfig * .95)));
+
+ // Expect only one broadcast despite always returning a size that should trigger broadcast.
+ p.flushIfNecessary(1, key, mockMetricsManager);
+ EXPECT_EQ(1, broadcastCount);
+
+ // This next call to flush should not trigger a broadcast.
+ p.mLastByteSizeTimes.clear(); // Force another check for byte size.
+ p.flushIfNecessary(2, key, mockMetricsManager);
+ EXPECT_EQ(1, broadcastCount);
+}
+
+TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge) {
+ sp<UidMap> m = new UidMap();
+ sp<AnomalyMonitor> anomalyMonitor;
+ int broadcastCount = 0;
+ StatsLogProcessor p(m, anomalyMonitor,
+ [&broadcastCount](const ConfigKey& key) { broadcastCount++; });
+
+ MockMetricsManager mockMetricsManager;
+
+ ConfigKey key(100, "key");
+ EXPECT_CALL(mockMetricsManager, byteSize())
+ .Times(1)
+ .WillRepeatedly(Return(int(StatsdStats::kMaxMetricsBytesPerConfig * 1.2)));
+
+ EXPECT_CALL(mockMetricsManager, onDumpReport()).Times(1);
+
+ // Expect to call the onDumpReport and skip the broadcast.
+ p.flushIfNecessary(1, key, mockMetricsManager);
+ EXPECT_EQ(0, broadcastCount);
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+} // namespace statsd
+} // namespace os
+} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index 0c19468..5b2cedd 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -15,6 +15,7 @@
#include "packages/UidMap.h"
#include "StatsLogProcessor.h"
#include "config/ConfigKey.h"
+#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
#include "statslog.h"
@@ -35,7 +36,8 @@
TEST(UidMapTest, TestIsolatedUID) {
sp<UidMap> m = new UidMap();
sp<AnomalyMonitor> anomalyMonitor;
- StatsLogProcessor p(m, anomalyMonitor, nullptr);
+ // Construct the processor with a dummy sendBroadcast function that does nothing.
+ StatsLogProcessor p(m, anomalyMonitor, [](const ConfigKey& key) {});
LogEvent addEvent(android::util::ISOLATED_UID_CHANGED, 1);
addEvent.write(100); // parent UID
addEvent.write(101); // isolated UID
@@ -59,7 +61,7 @@
TEST(UidMapTest, TestMatching) {
UidMap m;
vector<int32_t> uids;
- vector<int32_t> versions;
+ vector<int64_t> versions;
vector<String16> apps;
uids.push_back(1000);
@@ -77,7 +79,7 @@
TEST(UidMapTest, TestAddAndRemove) {
UidMap m;
vector<int32_t> uids;
- vector<int32_t> versions;
+ vector<int64_t> versions;
vector<String16> apps;
uids.push_back(1000);
@@ -105,7 +107,7 @@
m.OnConfigUpdated(config1);
vector<int32_t> uids;
- vector<int32_t> versions;
+ vector<int64_t> versions;
vector<String16> apps;
uids.push_back(1000);
uids.push_back(1000);
@@ -114,26 +116,34 @@
versions.push_back(4);
versions.push_back(5);
m.updateMap(1, uids, versions, apps);
+ EXPECT_EQ(1, m.mOutput.snapshots_size());
UidMapping results = m.getOutput(2, config1);
EXPECT_EQ(1, results.snapshots_size());
// It should be cleared now
+ EXPECT_EQ(0, m.mOutput.snapshots_size());
results = m.getOutput(3, config1);
EXPECT_EQ(0, results.snapshots_size());
// Now add another configuration.
m.OnConfigUpdated(config2);
m.updateApp(5, String16(kApp1.c_str()), 1000, 40);
+ EXPECT_EQ(1, m.mOutput.changes_size());
results = m.getOutput(6, config1);
EXPECT_EQ(0, results.snapshots_size());
EXPECT_EQ(1, results.changes_size());
+ EXPECT_EQ(1, m.mOutput.changes_size());
- // Now we still haven't been able to delete anything
+ // Add another delta update.
m.updateApp(7, String16(kApp2.c_str()), 1001, 41);
+ EXPECT_EQ(2, m.mOutput.changes_size());
+
+ // We still can't remove anything.
results = m.getOutput(8, config1);
EXPECT_EQ(0, results.snapshots_size());
EXPECT_EQ(2, results.changes_size());
+ EXPECT_EQ(2, m.mOutput.changes_size());
results = m.getOutput(9, config2);
EXPECT_EQ(0, results.snapshots_size());
@@ -142,6 +152,66 @@
EXPECT_EQ(0, m.mOutput.snapshots_size());
EXPECT_EQ(0, m.mOutput.changes_size());
}
+
+TEST(UidMapTest, TestMemoryComputed) {
+ UidMap m;
+
+ ConfigKey config1(1, "config1");
+ m.OnConfigUpdated(config1);
+
+ size_t startBytes = m.mBytesUsed;
+ vector<int32_t> uids;
+ vector<int64_t> versions;
+ vector<String16> apps;
+ uids.push_back(1000);
+ apps.push_back(String16(kApp1.c_str()));
+ versions.push_back(1);
+ m.updateMap(1, uids, versions, apps);
+ size_t snapshot_bytes = m.mBytesUsed;
+ EXPECT_TRUE(snapshot_bytes > startBytes);
+
+ m.updateApp(3, String16(kApp1.c_str()), 1000, 40);
+ EXPECT_TRUE(m.mBytesUsed > snapshot_bytes);
+ size_t bytesWithSnapshotChange = m.mBytesUsed;
+
+ m.getOutput(2, config1);
+ EXPECT_TRUE(m.mBytesUsed < bytesWithSnapshotChange);
+ size_t prevBytes = m.mBytesUsed;
+
+ m.getOutput(4, config1);
+ EXPECT_TRUE(m.mBytesUsed < prevBytes);
+}
+
+TEST(UidMapTest, TestMemoryGuardrail) {
+ UidMap m;
+ string buf;
+
+ ConfigKey config1(1, "config1");
+ m.OnConfigUpdated(config1);
+
+ size_t startBytes = m.mBytesUsed;
+ vector<int32_t> uids;
+ vector<int64_t> versions;
+ vector<String16> apps;
+ for (int i = 0; i < 100; i++) {
+ uids.push_back(1);
+ buf = "EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY." + to_string(i);
+ apps.push_back(String16(buf.c_str()));
+ versions.push_back(1);
+ }
+ m.updateMap(1, uids, versions, apps);
+ EXPECT_EQ(1, m.mOutput.snapshots_size());
+
+ m.updateApp(3, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 2);
+ EXPECT_EQ(1, m.mOutput.snapshots_size());
+ EXPECT_EQ(1, m.mOutput.changes_size());
+
+ // Now force deletion by limiting the memory to hold one delta change.
+ m.maxBytesOverride = 80; // Since the app string alone requires >45 characters.
+ m.updateApp(5, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 4);
+ EXPECT_EQ(0, m.mOutput.snapshots_size());
+ EXPECT_EQ(1, m.mOutput.changes_size());
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
index e0200f27..f385763 100644
--- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -30,6 +30,8 @@
namespace os {
namespace statsd {
+const ConfigKey kConfigKey(0, "test");
+
void AddValueToBucket(const std::vector<std::pair<string, long>>& key_value_pair_list,
std::shared_ptr<DimToValMap> bucket) {
for (auto itr = key_value_pair_list.begin(); itr != key_value_pair_list.end(); itr++) {
@@ -51,7 +53,7 @@
alert.set_refractory_period_secs(2 * bucketSizeNs / NS_PER_SEC);
alert.set_trigger_if_sum_gt(2);
- AnomalyTracker anomalyTracker(alert, bucketSizeNs);
+ AnomalyTracker anomalyTracker(alert, kConfigKey);
std::shared_ptr<DimToValMap> bucket0 = MockBucket({{"a", 1}, {"b", 2}, {"c", 1}});
int64_t eventTimestamp0 = 10;
@@ -168,7 +170,7 @@
alert.set_refractory_period_secs(2 * bucketSizeNs / NS_PER_SEC);
alert.set_trigger_if_sum_gt(2);
- AnomalyTracker anomalyTracker(alert, bucketSizeNs);
+ AnomalyTracker anomalyTracker(alert, kConfigKey);
std::shared_ptr<DimToValMap> bucket9 = MockBucket({{"a", 1}, {"b", 2}, {"c", 1}});
std::shared_ptr<DimToValMap> bucket16 = MockBucket({{"b", 4}});
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
index 92b4ffc..01ba82d 100644
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -30,21 +30,21 @@
const ConfigKey kConfigKey(0, "test");
-SimpleCondition getWakeLockHeldCondition(bool countNesting, bool defaultFalse,
+SimplePredicate getWakeLockHeldCondition(bool countNesting, bool defaultFalse,
bool outputSlicedUid) {
- SimpleCondition simpleCondition;
- simpleCondition.set_start("WAKE_LOCK_ACQUIRE");
- simpleCondition.set_stop("WAKE_LOCK_RELEASE");
- simpleCondition.set_stop_all("RELEASE_ALL");
+ SimplePredicate simplePredicate;
+ simplePredicate.set_start("WAKE_LOCK_ACQUIRE");
+ simplePredicate.set_stop("WAKE_LOCK_RELEASE");
+ simplePredicate.set_stop_all("RELEASE_ALL");
if (outputSlicedUid) {
- KeyMatcher* keyMatcher = simpleCondition.add_dimension();
+ KeyMatcher* keyMatcher = simplePredicate.add_dimension();
keyMatcher->set_key(1);
}
- simpleCondition.set_count_nesting(countNesting);
- simpleCondition.set_initial_value(defaultFalse ? SimpleCondition_InitialValue_FALSE
- : SimpleCondition_InitialValue_UNKNOWN);
- return simpleCondition;
+ simplePredicate.set_count_nesting(countNesting);
+ simplePredicate.set_initial_value(defaultFalse ? SimplePredicate_InitialValue_FALSE
+ : SimplePredicate_InitialValue_UNKNOWN);
+ return simplePredicate;
}
void makeWakeLockEvent(LogEvent* event, int uid, const string& wl, int acquire) {
@@ -68,18 +68,18 @@
}
TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) {
- SimpleCondition simpleCondition;
- simpleCondition.set_start("SCREEN_TURNED_ON");
- simpleCondition.set_stop("SCREEN_TURNED_OFF");
- simpleCondition.set_count_nesting(false);
- simpleCondition.set_initial_value(SimpleCondition_InitialValue_UNKNOWN);
+ SimplePredicate simplePredicate;
+ simplePredicate.set_start("SCREEN_TURNED_ON");
+ simplePredicate.set_stop("SCREEN_TURNED_OFF");
+ simplePredicate.set_count_nesting(false);
+ simplePredicate.set_initial_value(SimplePredicate_InitialValue_UNKNOWN);
unordered_map<string, int> trackerNameIndexMap;
trackerNameIndexMap["SCREEN_TURNED_ON"] = 0;
trackerNameIndexMap["SCREEN_TURNED_OFF"] = 1;
SimpleConditionTracker conditionTracker(kConfigKey, "SCREEN_IS_ON", 0 /*tracker index*/,
- simpleCondition, trackerNameIndexMap);
+ simplePredicate, trackerNameIndexMap);
LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
@@ -87,11 +87,11 @@
matcherState.push_back(MatchingState::kNotMatched);
matcherState.push_back(MatchingState::kNotMatched);
- vector<sp<ConditionTracker>> allConditions;
+ vector<sp<ConditionTracker>> allPredicates;
vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
vector<bool> changedCache(1, false);
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
// not matched start or stop. condition doesn't change
EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]);
@@ -104,7 +104,7 @@
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
// now condition should change to true.
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
@@ -117,7 +117,7 @@
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
EXPECT_FALSE(changedCache[0]);
@@ -129,7 +129,7 @@
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
// condition changes to false.
@@ -143,7 +143,7 @@
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
// condition should still be false. not changed.
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
@@ -151,17 +151,17 @@
}
TEST(SimpleConditionTrackerTest, TestNonSlicedConditionNestCounting) {
- SimpleCondition simpleCondition;
- simpleCondition.set_start("SCREEN_TURNED_ON");
- simpleCondition.set_stop("SCREEN_TURNED_OFF");
- simpleCondition.set_count_nesting(true);
+ SimplePredicate simplePredicate;
+ simplePredicate.set_start("SCREEN_TURNED_ON");
+ simplePredicate.set_stop("SCREEN_TURNED_OFF");
+ simplePredicate.set_count_nesting(true);
unordered_map<string, int> trackerNameIndexMap;
trackerNameIndexMap["SCREEN_TURNED_ON"] = 0;
trackerNameIndexMap["SCREEN_TURNED_OFF"] = 1;
SimpleConditionTracker conditionTracker(kConfigKey, "SCREEN_IS_ON",
- 0 /*condition tracker index*/, simpleCondition,
+ 0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
@@ -170,11 +170,11 @@
vector<MatchingState> matcherState;
matcherState.push_back(MatchingState::kMatched);
matcherState.push_back(MatchingState::kNotMatched);
- vector<sp<ConditionTracker>> allConditions;
+ vector<sp<ConditionTracker>> allPredicates;
vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
vector<bool> changedCache(1, false);
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
@@ -187,7 +187,7 @@
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
@@ -200,7 +200,7 @@
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
// result should still be true
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
@@ -213,7 +213,7 @@
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
// result should still be true
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
@@ -221,7 +221,7 @@
}
TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
- SimpleCondition simpleCondition = getWakeLockHeldCondition(
+ SimplePredicate simplePredicate = getWakeLockHeldCondition(
true /*nesting*/, true /*default to false*/, true /*output slice by uid*/);
string conditionName = "WL_HELD_BY_UID2";
@@ -231,7 +231,7 @@
trackerNameIndexMap["RELEASE_ALL"] = 2;
SimpleConditionTracker conditionTracker(kConfigKey, conditionName,
- 0 /*condition tracker index*/, simpleCondition,
+ 0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
int uid = 111;
@@ -242,11 +242,12 @@
vector<MatchingState> matcherState;
matcherState.push_back(MatchingState::kMatched);
matcherState.push_back(MatchingState::kNotMatched);
- vector<sp<ConditionTracker>> allConditions;
+ matcherState.push_back(MatchingState::kNotMatched);
+ vector<sp<ConditionTracker>> allPredicates;
vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
vector<bool> changedCache(1, false);
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
@@ -256,7 +257,7 @@
const auto queryKey = getWakeLockQueryKey(1, uid, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ conditionTracker.isConditionMet(queryKey, allPredicates, conditionCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
// another wake lock acquired by this uid
@@ -267,7 +268,7 @@
matcherState.push_back(MatchingState::kNotMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event2, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_FALSE(changedCache[0]);
@@ -279,7 +280,7 @@
matcherState.push_back(MatchingState::kMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event3, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
changedCache);
// nothing changes, because wake lock 2 is still held for this uid
EXPECT_FALSE(changedCache[0]);
@@ -291,19 +292,19 @@
matcherState.push_back(MatchingState::kMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event4, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
EXPECT_TRUE(changedCache[0]);
// query again
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ conditionTracker.isConditionMet(queryKey, allPredicates, conditionCache);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
}
TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
- SimpleCondition simpleCondition = getWakeLockHeldCondition(
+ SimplePredicate simplePredicate = getWakeLockHeldCondition(
true /*nesting*/, true /*default to false*/, false /*slice output by uid*/);
string conditionName = "WL_HELD";
@@ -313,7 +314,7 @@
trackerNameIndexMap["RELEASE_ALL"] = 2;
SimpleConditionTracker conditionTracker(kConfigKey, conditionName,
- 0 /*condition tracker index*/, simpleCondition,
+ 0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
int uid1 = 111;
string uid1_wl1 = "wl1_1";
@@ -327,11 +328,12 @@
vector<MatchingState> matcherState;
matcherState.push_back(MatchingState::kMatched);
matcherState.push_back(MatchingState::kNotMatched);
- vector<sp<ConditionTracker>> allConditions;
+ matcherState.push_back(MatchingState::kNotMatched);
+ vector<sp<ConditionTracker>> allPredicates;
vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
vector<bool> changedCache(1, false);
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
@@ -341,7 +343,7 @@
map<string, HashableDimensionKey> queryKey;
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ conditionTracker.isConditionMet(queryKey, allPredicates, conditionCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
// another wake lock acquired by this uid
@@ -352,7 +354,7 @@
matcherState.push_back(MatchingState::kNotMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event2, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_FALSE(changedCache[0]);
@@ -364,7 +366,7 @@
matcherState.push_back(MatchingState::kMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event3, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
changedCache);
// nothing changes, because uid2 is still holding wl.
EXPECT_FALSE(changedCache[0]);
@@ -376,19 +378,19 @@
matcherState.push_back(MatchingState::kMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event4, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
EXPECT_TRUE(changedCache[0]);
// query again
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ conditionTracker.isConditionMet(queryKey, allPredicates, conditionCache);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
}
TEST(SimpleConditionTrackerTest, TestStopAll) {
- SimpleCondition simpleCondition = getWakeLockHeldCondition(
+ SimplePredicate simplePredicate = getWakeLockHeldCondition(
true /*nesting*/, true /*default to false*/, true /*output slice by uid*/);
string conditionName = "WL_HELD_BY_UID3";
@@ -398,7 +400,7 @@
trackerNameIndexMap["RELEASE_ALL"] = 2;
SimpleConditionTracker conditionTracker(kConfigKey, conditionName,
- 0 /*condition tracker index*/, simpleCondition,
+ 0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
int uid1 = 111;
int uid2 = 222;
@@ -411,11 +413,11 @@
matcherState.push_back(MatchingState::kMatched);
matcherState.push_back(MatchingState::kNotMatched);
matcherState.push_back(MatchingState::kNotMatched);
- vector<sp<ConditionTracker>> allConditions;
+ vector<sp<ConditionTracker>> allPredicates;
vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
vector<bool> changedCache(1, false);
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
@@ -425,7 +427,7 @@
const auto queryKey = getWakeLockQueryKey(1, uid1, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ conditionTracker.isConditionMet(queryKey, allPredicates, conditionCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
// another wake lock acquired by uid2
@@ -437,7 +439,7 @@
matcherState.push_back(MatchingState::kNotMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event2, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(2UL, conditionTracker.mSlicedConditionState.size());
EXPECT_TRUE(changedCache[0]);
@@ -446,7 +448,7 @@
const auto queryKey2 = getWakeLockQueryKey(1, uid2, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ conditionTracker.isConditionMet(queryKey, allPredicates, conditionCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
@@ -459,7 +461,7 @@
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event3, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_TRUE(changedCache[0]);
EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
@@ -468,14 +470,14 @@
const auto queryKey3 = getWakeLockQueryKey(1, uid1, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ conditionTracker.isConditionMet(queryKey, allPredicates, conditionCache);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
// TEST QUERY
const auto queryKey4 = getWakeLockQueryKey(1, uid2, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ conditionTracker.isConditionMet(queryKey, allPredicates, conditionCache);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
}
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
index 286f6bd..9fed4f8 100644
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -13,8 +13,10 @@
// limitations under the License.
#include "src/guardrail/StatsdStats.h"
+#include "statslog.h"
#include <gtest/gtest.h>
+#include <vector>
#ifdef __ANDROID__
@@ -22,24 +24,276 @@
namespace os {
namespace statsd {
-TEST(StatsdStatsTest, TestConfigAdd) {
- // TODO: implement
+using std::vector;
+
+TEST(StatsdStatsTest, TestValidConfigAdd) {
+ StatsdStats stats;
+ string name = "StatsdTest";
+ ConfigKey key(0, name);
+ const int metricsCount = 10;
+ const int conditionsCount = 20;
+ const int matchersCount = 30;
+ const int alertsCount = 10;
+ stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount,
+ true /*valid config*/);
+ vector<uint8_t> output;
+ stats.dumpStats(&output, false /*reset stats*/);
+
+ StatsdStatsReport report;
+ bool good = report.ParseFromArray(&output[0], output.size());
+ EXPECT_TRUE(good);
+ EXPECT_EQ(1, report.config_stats_size());
+ const auto& configReport = report.config_stats(0);
+ EXPECT_EQ(0, configReport.uid());
+ EXPECT_EQ(name, configReport.name());
+ EXPECT_EQ(metricsCount, configReport.metric_count());
+ EXPECT_EQ(conditionsCount, configReport.condition_count());
+ EXPECT_EQ(matchersCount, configReport.matcher_count());
+ EXPECT_EQ(alertsCount, configReport.alert_count());
+ EXPECT_EQ(true, configReport.is_valid());
+ EXPECT_FALSE(configReport.has_deletion_time_sec());
+}
+
+TEST(StatsdStatsTest, TestInvalidConfigAdd) {
+ StatsdStats stats;
+ string name = "StatsdTest";
+ ConfigKey key(0, name);
+ const int metricsCount = 10;
+ const int conditionsCount = 20;
+ const int matchersCount = 30;
+ const int alertsCount = 10;
+ stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount,
+ false /*bad config*/);
+ vector<uint8_t> output;
+ stats.dumpStats(&output, false);
+
+ StatsdStatsReport report;
+ bool good = report.ParseFromArray(&output[0], output.size());
+ EXPECT_TRUE(good);
+ EXPECT_EQ(1, report.config_stats_size());
+ const auto& configReport = report.config_stats(0);
+ // The invalid config should be put into icebox with a deletion time.
+ EXPECT_TRUE(configReport.has_deletion_time_sec());
}
TEST(StatsdStatsTest, TestConfigRemove) {
- // TODO: implement
+ StatsdStats stats;
+ string name = "StatsdTest";
+ ConfigKey key(0, name);
+ const int metricsCount = 10;
+ const int conditionsCount = 20;
+ const int matchersCount = 30;
+ const int alertsCount = 10;
+ stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, true);
+ vector<uint8_t> output;
+ stats.dumpStats(&output, false);
+ StatsdStatsReport report;
+ bool good = report.ParseFromArray(&output[0], output.size());
+ EXPECT_TRUE(good);
+ EXPECT_EQ(1, report.config_stats_size());
+ const auto& configReport = report.config_stats(0);
+ EXPECT_FALSE(configReport.has_deletion_time_sec());
+
+ stats.noteConfigRemoved(key);
+ stats.dumpStats(&output, false);
+ good = report.ParseFromArray(&output[0], output.size());
+ EXPECT_TRUE(good);
+ EXPECT_EQ(1, report.config_stats_size());
+ const auto& configReport2 = report.config_stats(0);
+ EXPECT_TRUE(configReport2.has_deletion_time_sec());
}
-TEST(StatsdStatsTest, TestMatcherReport) {
- // TODO: implement
-}
+TEST(StatsdStatsTest, TestSubStats) {
+ StatsdStats stats;
+ ConfigKey key(0, "test");
+ stats.noteConfigReceived(key, 2, 3, 4, 5, true);
-TEST(StatsdStatsTest, TestConditionReport) {
- // TODO: implement
+ stats.noteMatcherMatched(key, "matcher1");
+ stats.noteMatcherMatched(key, "matcher1");
+ stats.noteMatcherMatched(key, "matcher2");
+
+ stats.noteConditionDimensionSize(key, "condition1", 250);
+ stats.noteConditionDimensionSize(key, "condition1", 240);
+
+ stats.noteMetricDimensionSize(key, "metric1", 201);
+ stats.noteMetricDimensionSize(key, "metric1", 202);
+
+ stats.noteAnomalyDeclared(key, "alert1");
+ stats.noteAnomalyDeclared(key, "alert1");
+ stats.noteAnomalyDeclared(key, "alert2");
+
+ // broadcast-> 2
+ stats.noteBroadcastSent(key);
+ stats.noteBroadcastSent(key);
+
+ // data drop -> 1
+ stats.noteDataDropped(key);
+
+ // dump report -> 3
+ stats.noteMetricsReportSent(key);
+ stats.noteMetricsReportSent(key);
+ stats.noteMetricsReportSent(key);
+
+ vector<uint8_t> output;
+ stats.dumpStats(&output, true); // Dump and reset stats
+ StatsdStatsReport report;
+ bool good = report.ParseFromArray(&output[0], output.size());
+ EXPECT_TRUE(good);
+ EXPECT_EQ(1, report.config_stats_size());
+ const auto& configReport = report.config_stats(0);
+ EXPECT_EQ(2, configReport.broadcast_sent_time_sec_size());
+ EXPECT_EQ(1, configReport.data_drop_time_sec_size());
+ EXPECT_EQ(3, configReport.dump_report_time_sec_size());
+
+ EXPECT_EQ(2, configReport.matcher_stats_size());
+ // matcher1 is the first in the list
+ if (!configReport.matcher_stats(0).name().compare("matcher1")) {
+ EXPECT_EQ(2, configReport.matcher_stats(0).matched_times());
+ EXPECT_EQ(1, configReport.matcher_stats(1).matched_times());
+ EXPECT_EQ("matcher2", configReport.matcher_stats(1).name());
+ } else {
+ // matcher1 is the second in the list.
+ EXPECT_EQ(1, configReport.matcher_stats(0).matched_times());
+ EXPECT_EQ("matcher2", configReport.matcher_stats(0).name());
+
+ EXPECT_EQ(2, configReport.matcher_stats(1).matched_times());
+ EXPECT_EQ("matcher1", configReport.matcher_stats(1).name());
+ }
+
+ EXPECT_EQ(2, configReport.alert_stats_size());
+ bool alert1first = !configReport.alert_stats(0).name().compare("alert1");
+ EXPECT_EQ("alert1", configReport.alert_stats(alert1first ? 0 : 1).name());
+ EXPECT_EQ(2, configReport.alert_stats(alert1first ? 0 : 1).declared_times());
+ EXPECT_EQ("alert2", configReport.alert_stats(alert1first ? 1 : 0).name());
+ EXPECT_EQ(1, configReport.alert_stats(alert1first ? 1 : 0).declared_times());
+
+ EXPECT_EQ(1, configReport.condition_stats_size());
+ EXPECT_EQ("condition1", configReport.condition_stats(0).name());
+ EXPECT_EQ(250, configReport.condition_stats(0).max_tuple_counts());
+
+ EXPECT_EQ(1, configReport.metric_stats_size());
+ EXPECT_EQ("metric1", configReport.metric_stats(0).name());
+ EXPECT_EQ(202, configReport.metric_stats(0).max_tuple_counts());
+
+ // after resetting the stats, some new events come
+ stats.noteMatcherMatched(key, "matcher99");
+ stats.noteConditionDimensionSize(key, "condition99", 300);
+ stats.noteMetricDimensionSize(key, "metric99", 270);
+ stats.noteAnomalyDeclared(key, "alert99");
+
+ // now the config stats should only contain the stats about the new event.
+ stats.dumpStats(&output, false);
+ good = report.ParseFromArray(&output[0], output.size());
+ EXPECT_TRUE(good);
+ EXPECT_EQ(1, report.config_stats_size());
+ const auto& configReport2 = report.config_stats(0);
+ EXPECT_EQ(1, configReport2.matcher_stats_size());
+ EXPECT_EQ("matcher99", configReport2.matcher_stats(0).name());
+ EXPECT_EQ(1, configReport2.matcher_stats(0).matched_times());
+
+ EXPECT_EQ(1, configReport2.condition_stats_size());
+ EXPECT_EQ("condition99", configReport2.condition_stats(0).name());
+ EXPECT_EQ(300, configReport2.condition_stats(0).max_tuple_counts());
+
+ EXPECT_EQ(1, configReport2.metric_stats_size());
+ EXPECT_EQ("metric99", configReport2.metric_stats(0).name());
+ EXPECT_EQ(270, configReport2.metric_stats(0).max_tuple_counts());
+
+ EXPECT_EQ(1, configReport2.alert_stats_size());
+ EXPECT_EQ("alert99", configReport2.alert_stats(0).name());
+ EXPECT_EQ(1, configReport2.alert_stats(0).declared_times());
}
TEST(StatsdStatsTest, TestAtomLog) {
- // TODO: implement
+ StatsdStats stats;
+ time_t now = time(nullptr);
+ // old event, we get it from the stats buffer. should be ignored.
+ stats.noteAtomLogged(android::util::SENSOR_STATE_CHANGED, 1000);
+
+ stats.noteAtomLogged(android::util::SENSOR_STATE_CHANGED, now + 1);
+ stats.noteAtomLogged(android::util::SENSOR_STATE_CHANGED, now + 2);
+ stats.noteAtomLogged(android::util::DROPBOX_ERROR_CHANGED, now + 3);
+ // pulled event, should ignore
+ stats.noteAtomLogged(android::util::WIFI_BYTES_TRANSFERRED, now + 4);
+
+ vector<uint8_t> output;
+ stats.dumpStats(&output, false);
+ StatsdStatsReport report;
+ bool good = report.ParseFromArray(&output[0], output.size());
+ EXPECT_TRUE(good);
+
+ EXPECT_EQ(2, report.atom_stats_size());
+ bool sensorAtomGood = false;
+ bool dropboxAtomGood = false;
+
+ for (const auto& atomStats : report.atom_stats()) {
+ if (atomStats.tag() == android::util::SENSOR_STATE_CHANGED && atomStats.count() == 2) {
+ sensorAtomGood = true;
+ }
+ if (atomStats.tag() == android::util::DROPBOX_ERROR_CHANGED && atomStats.count() == 1) {
+ dropboxAtomGood = true;
+ }
+ }
+
+ EXPECT_TRUE(dropboxAtomGood);
+ EXPECT_TRUE(sensorAtomGood);
+}
+
+
+TEST(StatsdStatsTest, TestAnomalyMonitor) {
+ StatsdStats stats;
+ stats.noteRegisteredAnomalyAlarmChanged();
+ stats.noteRegisteredAnomalyAlarmChanged();
+
+ vector<uint8_t> output;
+ stats.dumpStats(&output, false);
+ StatsdStatsReport report;
+ bool good = report.ParseFromArray(&output[0], output.size());
+ EXPECT_TRUE(good);
+
+ EXPECT_EQ(2, report.anomaly_alarm_stats().alarms_registered());
+}
+
+TEST(StatsdStatsTest, TestTimestampThreshold) {
+ StatsdStats stats;
+ vector<int32_t> timestamps;
+ for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
+ timestamps.push_back(i);
+ }
+ ConfigKey key(0, "test");
+ stats.noteConfigReceived(key, 2, 3, 4, 5, true);
+
+ for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
+ stats.noteDataDropped(key, timestamps[i]);
+ stats.noteBroadcastSent(key, timestamps[i]);
+ stats.noteMetricsReportSent(key, timestamps[i]);
+ }
+
+ int32_t newTimestamp = 10000;
+
+ // now it should trigger removing oldest timestamp
+ stats.noteDataDropped(key, 10000);
+ stats.noteBroadcastSent(key, 10000);
+ stats.noteMetricsReportSent(key, 10000);
+
+ EXPECT_TRUE(stats.mConfigStats.find(key) != stats.mConfigStats.end());
+ const auto& configStats = stats.mConfigStats[key];
+
+ int maxCount = StatsdStats::kMaxTimestampCount;
+ EXPECT_EQ(maxCount, configStats.broadcast_sent_time_sec_size());
+ EXPECT_EQ(maxCount, configStats.data_drop_time_sec_size());
+ EXPECT_EQ(maxCount, configStats.dump_report_time_sec_size());
+
+ // the oldest timestamp is the second timestamp in history
+ EXPECT_EQ(1, configStats.broadcast_sent_time_sec(0));
+ EXPECT_EQ(1, configStats.broadcast_sent_time_sec(0));
+ EXPECT_EQ(1, configStats.broadcast_sent_time_sec(0));
+
+ // the last timestamp is the newest timestamp.
+ EXPECT_EQ(newTimestamp,
+ configStats.broadcast_sent_time_sec(StatsdStats::kMaxTimestampCount - 1));
+ EXPECT_EQ(newTimestamp, configStats.data_drop_time_sec(StatsdStats::kMaxTimestampCount - 1));
+ EXPECT_EQ(newTimestamp, configStats.dump_report_time_sec(StatsdStats::kMaxTimestampCount - 1));
}
} // namespace statsd
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index df74364..d973ba1 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -58,11 +58,11 @@
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2, false);
// Flushes at event #2.
- countProducer.flushIfNeeded(bucketStartTimeNs + 2);
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + 2);
EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
// Flushes.
- countProducer.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
countProducer.mPastBuckets.end());
@@ -75,7 +75,7 @@
// 1 matched event happens in bucket 2.
LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 2);
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3, false);
- countProducer.flushIfNeeded(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
countProducer.mPastBuckets.end());
@@ -86,7 +86,7 @@
EXPECT_EQ(1LL, bucketInfo2.mCount);
// nothing happens in bucket 3. we should not record anything for bucket 3.
- countProducer.flushIfNeeded(bucketStartTimeNs + 3 * bucketSizeNs + 1);
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
countProducer.mPastBuckets.end());
@@ -119,7 +119,7 @@
countProducer.onMatchedLogEvent(1 /*matcher index*/, event2, false /*pulled*/);
EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
- countProducer.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
countProducer.mPastBuckets.end());
@@ -141,9 +141,9 @@
metric.set_name("1");
metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
metric.set_condition("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON");
- EventConditionLink* link = metric.add_links();
+ MetricConditionLink* link = metric.add_links();
link->set_condition("APP_IN_BACKGROUND_PER_UID");
- link->add_key_in_main()->set_key(1);
+ link->add_key_in_what()->set_key(1);
link->add_key_in_condition()->set_key(2);
LogEvent event1(1, bucketStartTimeNs + 1);
@@ -167,11 +167,11 @@
bucketStartTimeNs);
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1, false);
- countProducer.flushIfNeeded(bucketStartTimeNs + 1);
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2, false);
- countProducer.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
countProducer.mPastBuckets.end());
@@ -196,7 +196,7 @@
int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
- sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, bucketSizeNs);
+ sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
CountMetric metric;
metric.set_name("1");
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
new file mode 100644
index 0000000..3158c27
--- /dev/null
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -0,0 +1,121 @@
+// 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.
+
+#include "src/metrics/DurationMetricProducer.h"
+#include "metrics_test_helper.h"
+#include "src/condition/ConditionWizard.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <set>
+#include <unordered_map>
+#include <vector>
+
+using namespace android::os::statsd;
+using namespace testing;
+using android::sp;
+using std::set;
+using std::unordered_map;
+using std::vector;
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+const ConfigKey kConfigKey(0, "test");
+
+TEST(DurationMetricTrackerTest, TestNoCondition) {
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ DurationMetric metric;
+ metric.set_name("1");
+ metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
+ metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+ int tagId = 1;
+ LogEvent event1(tagId, bucketStartTimeNs + 1);
+ LogEvent event2(tagId, bucketStartTimeNs + bucketSizeNs + 2);
+
+ DurationMetricProducer durationProducer(
+ kConfigKey, metric, -1 /*no condition*/, 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard, {}, bucketStartTimeNs);
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1, false /* scheduledPull */);
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2, false /* scheduledPull */);
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
+ EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
+ durationProducer.mPastBuckets.end());
+ const auto& buckets = durationProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
+ EXPECT_EQ(2UL, buckets.size());
+ EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
+ EXPECT_EQ(bucketSizeNs - 1ULL, buckets[0].mDuration);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[1].mBucketEndNs);
+ EXPECT_EQ(2ULL, buckets[1].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ DurationMetric metric;
+ metric.set_name("1");
+ metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
+ metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+ int tagId = 1;
+ LogEvent event1(tagId, bucketStartTimeNs + 1);
+ LogEvent event2(tagId, bucketStartTimeNs + 2);
+ LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 1);
+ LogEvent event4(tagId, bucketStartTimeNs + bucketSizeNs + 3);
+
+ DurationMetricProducer durationProducer(
+ kConfigKey, metric, 0 /* condition index */, 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard, {}, bucketStartTimeNs);
+ EXPECT_FALSE(durationProducer.mCondition);
+ EXPECT_FALSE(durationProducer.isConditionSliced());
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1, false /* scheduledPull */);
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2, false /* scheduledPull */);
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event3, false /* scheduledPull */);
+ durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event4, false /* scheduledPull */);
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
+ EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
+ durationProducer.mPastBuckets.end());
+ const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets2.size());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
+ EXPECT_EQ(1ULL, buckets2[0].mDuration);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
index 724ad59..f3302fd 100644
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -91,9 +91,9 @@
EventMetric metric;
metric.set_name("1");
metric.set_condition("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON");
- EventConditionLink* link = metric.add_links();
+ MetricConditionLink* link = metric.add_links();
link->set_condition("APP_IN_BACKGROUND_PER_UID");
- link->add_key_in_main()->set_key(1);
+ link->add_key_in_what()->set_key(1);
link->add_key_in_condition()->set_key(2);
LogEvent event1(1, bucketStartTimeNs + 1);
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index b9e2b8a..59475d2 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -33,6 +33,8 @@
namespace os {
namespace statsd {
+const ConfigKey kConfigKey(0, "test");
+
TEST(GaugeMetricProducerTest, TestWithCondition) {
int64_t bucketStartTimeNs = 10000000000;
int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL;
@@ -60,7 +62,7 @@
allData.push_back(event2);
gaugeProducer.onDataPulled(allData);
- gaugeProducer.flushIfNeeded(event2->GetTimestampNs() + 1);
+ gaugeProducer.flushIfNeededLocked(event2->GetTimestampNs() + 1);
EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
@@ -74,7 +76,7 @@
event3->init();
allData.push_back(event3);
gaugeProducer.onDataPulled(allData);
- gaugeProducer.flushIfNeeded(bucketStartTimeNs + 2 * bucketSizeNs + 10);
+ gaugeProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 10);
EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
EXPECT_EQ(25L, gaugeProducer.mCurrentSlicedBucket->begin()->second);
// One dimension.
@@ -148,7 +150,7 @@
alert.set_metric_name("1");
alert.set_trigger_if_sum_gt(25);
alert.set_number_of_buckets(2);
- sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, bucketSizeNs);
+ sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
gaugeProducer.addAnomalyTracker(anomalyTracker);
std::shared_ptr<LogEvent> event1 = std::make_shared<LogEvent>(1, bucketStartTimeNs + 1);
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index 0763c94..4e5e0d6 100644
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -37,18 +37,19 @@
namespace statsd {
const ConfigKey kConfigKey(0, "test");
+const string eventKey = "event";
TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
ConditionKey key1;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, false, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, false, bucketStartTimeNs,
+ bucketSizeNs, {});
tracker.noteStart("1", true, bucketStartTimeNs, key1);
// Event starts again. This would not change anything as it already starts.
@@ -60,50 +61,53 @@
tracker.noteStart("2", true, bucketStartTimeNs + 20, key1);
tracker.noteStop("2", bucketStartTimeNs + 40, false /*stop all*/);
- tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(20ULL, buckets[0].mDuration);
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(1u, buckets[eventKey].size());
+ EXPECT_EQ(20ULL, buckets[eventKey][0].mDuration);
}
TEST(MaxDurationTrackerTest, TestStopAll) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
ConditionKey key1;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, false, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, false, bucketStartTimeNs,
+ bucketSizeNs, {});
tracker.noteStart("1", true, bucketStartTimeNs + 1, key1);
// Another event starts in this bucket.
tracker.noteStart("2", true, bucketStartTimeNs + 20, key1);
- tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 40);
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 40, &buckets);
tracker.noteStopAll(bucketStartTimeNs + bucketSizeNs + 40);
EXPECT_TRUE(tracker.mInfos.empty());
- EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(bucketSizeNs - 1, buckets[0].mDuration);
- tracker.flushIfNeeded(bucketStartTimeNs + 3 * bucketSizeNs + 40);
- EXPECT_EQ(2u, buckets.size());
- EXPECT_EQ(bucketSizeNs - 1, buckets[0].mDuration);
- EXPECT_EQ(40ULL, buckets[1].mDuration);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(1u, buckets[eventKey].size());
+ EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
+
+ tracker.flushIfNeeded(bucketStartTimeNs + 3 * bucketSizeNs + 40, &buckets);
+ EXPECT_EQ(2u, buckets[eventKey].size());
+ EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
+ EXPECT_EQ(40ULL, buckets[eventKey][1].mDuration);
}
TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
ConditionKey key1;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, false, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, false, bucketStartTimeNs,
+ bucketSizeNs, {});
// The event starts.
tracker.noteStart("", true, bucketStartTimeNs + 1, key1);
@@ -112,25 +116,26 @@
tracker.noteStart("", true, bucketStartTimeNs + bucketSizeNs + 1, key1);
// The event stops at early 4th bucket.
- tracker.flushIfNeeded(bucketStartTimeNs + (3 * bucketSizeNs) + 20);
+ tracker.flushIfNeeded(bucketStartTimeNs + (3 * bucketSizeNs) + 20, &buckets);
tracker.noteStop("", bucketStartTimeNs + (3 * bucketSizeNs) + 20, false /*stop all*/);
- EXPECT_EQ(3u, buckets.size());
- EXPECT_EQ((unsigned long long)(bucketSizeNs - 1), buckets[0].mDuration);
- EXPECT_EQ((unsigned long long)bucketSizeNs, buckets[1].mDuration);
- EXPECT_EQ((unsigned long long)bucketSizeNs, buckets[2].mDuration);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(3u, buckets[eventKey].size());
+ EXPECT_EQ((unsigned long long)(bucketSizeNs - 1), buckets[eventKey][0].mDuration);
+ EXPECT_EQ((unsigned long long)bucketSizeNs, buckets[eventKey][1].mDuration);
+ EXPECT_EQ((unsigned long long)bucketSizeNs, buckets[eventKey][2].mDuration);
}
TEST(MaxDurationTrackerTest, TestCrossBucketBoundary_nested) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
ConditionKey key1;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, true, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, true, bucketStartTimeNs,
+ bucketSizeNs, {});
// 2 starts
tracker.noteStart("", true, bucketStartTimeNs + 1, key1);
@@ -138,20 +143,21 @@
// one stop
tracker.noteStop("", bucketStartTimeNs + 20, false /*stop all*/);
- tracker.flushIfNeeded(bucketStartTimeNs + (2 * bucketSizeNs) + 1);
+ tracker.flushIfNeeded(bucketStartTimeNs + (2 * bucketSizeNs) + 1, &buckets);
- EXPECT_EQ(2u, buckets.size());
- EXPECT_EQ(bucketSizeNs - 1, buckets[0].mDuration);
- EXPECT_EQ(bucketSizeNs, buckets[1].mDuration);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(2u, buckets[eventKey].size());
+ EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
+ EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
// real stop now.
tracker.noteStop("", bucketStartTimeNs + (2 * bucketSizeNs) + 5, false);
- tracker.flushIfNeeded(bucketStartTimeNs + (3 * bucketSizeNs) + 1);
+ tracker.flushIfNeeded(bucketStartTimeNs + (3 * bucketSizeNs) + 1, &buckets);
- EXPECT_EQ(3u, buckets.size());
- EXPECT_EQ(bucketSizeNs - 1, buckets[0].mDuration);
- EXPECT_EQ(bucketSizeNs, buckets[1].mDuration);
- EXPECT_EQ(5ULL, buckets[2].mDuration);
+ EXPECT_EQ(3u, buckets[eventKey].size());
+ EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
+ EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
+ EXPECT_EQ(5ULL, buckets[eventKey][2].mDuration);
}
TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
@@ -163,15 +169,15 @@
EXPECT_CALL(*wizard, query(_, key1)) // #4
.WillOnce(Return(ConditionState::kFalse));
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
int64_t durationTimeNs = 2 * 1000;
- MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, false, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false, bucketStartTimeNs,
+ bucketSizeNs, {});
EXPECT_TRUE(tracker.mAnomalyTrackers.empty());
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
@@ -180,9 +186,10 @@
tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs, false);
- tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(5ULL, buckets[0].mDuration);
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(1u, buckets[eventKey].size());
+ EXPECT_EQ(5ULL, buckets[eventKey][0].mDuration);
}
TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
@@ -193,7 +200,7 @@
alert.set_number_of_buckets(2);
alert.set_refractory_period_secs(1);
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
key1["APP_BACKGROUND"] = "1:maps|";
@@ -201,9 +208,9 @@
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
- sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, bucketSizeNs);
- MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, true, bucketStartTimeNs,
- bucketSizeNs, {anomalyTracker}, buckets);
+ sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
+ MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, true, bucketStartTimeNs,
+ bucketSizeNs, {anomalyTracker});
tracker.noteStart("1", true, eventStartTimeNs, key1);
tracker.noteStop("1", eventStartTimeNs + 10, false);
@@ -211,7 +218,7 @@
EXPECT_EQ(10LL, tracker.mDuration);
tracker.noteStart("2", true, eventStartTimeNs + 20, key1);
- tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC);
+ tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC, &buckets);
tracker.noteStop("2", eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC, false);
EXPECT_EQ((long long)(4 * NS_PER_SEC + 1LL), tracker.mDuration);
EXPECT_EQ(anomalyTracker->mLastAlarmTimestampNs,
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 63a0e2b..99d3e05 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -35,6 +35,7 @@
namespace statsd {
const ConfigKey kConfigKey(0, "test");
+const string eventKey = "event";
TEST(OringDurationTrackerTest, TestDurationOverlap) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
@@ -42,15 +43,15 @@
ConditionKey key1;
key1["APP_BACKGROUND"] = "1:maps|";
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t durationTimeNs = 2 * 1000;
- OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, false, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
+ bucketStartTimeNs, bucketSizeNs, {});
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
@@ -58,9 +59,11 @@
EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs, false);
- tracker.flushIfNeeded(eventStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(durationTimeNs, buckets[0].mDuration);
+ tracker.flushIfNeeded(eventStartTimeNs + bucketSizeNs + 1, &buckets);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+
+ EXPECT_EQ(1u, buckets[eventKey].size());
+ EXPECT_EQ(durationTimeNs, buckets[eventKey][0].mDuration);
}
TEST(OringDurationTrackerTest, TestDurationNested) {
@@ -69,14 +72,14 @@
ConditionKey key1;
key1["APP_BACKGROUND"] = "1:maps|";
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+ bucketSizeNs, {});
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
tracker.noteStart("2:maps", true, eventStartTimeNs + 10, key1); // overlapping wl
@@ -84,9 +87,10 @@
tracker.noteStop("2:maps", eventStartTimeNs + 2000, false);
tracker.noteStop("2:maps", eventStartTimeNs + 2003, false);
- tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(2003ULL, buckets[0].mDuration);
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(1u, buckets[eventKey].size());
+ EXPECT_EQ(2003ULL, buckets[eventKey][0].mDuration);
}
TEST(OringDurationTrackerTest, TestStopAll) {
@@ -95,23 +99,24 @@
ConditionKey key1;
key1["APP_BACKGROUND"] = "1:maps|";
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+ bucketSizeNs, {});
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
tracker.noteStart("3:maps", true, eventStartTimeNs + 10, key1); // overlapping wl
tracker.noteStopAll(eventStartTimeNs + 2003);
- tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(2003ULL, buckets[0].mDuration);
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(1u, buckets[eventKey].size());
+ EXPECT_EQ(2003ULL, buckets[eventKey][0].mDuration);
}
TEST(OringDurationTrackerTest, TestCrossBucketBoundary) {
@@ -120,32 +125,33 @@
ConditionKey key1;
key1["APP_BACKGROUND"] = "1:maps|";
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t durationTimeNs = 2 * 1000;
- OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+ bucketSizeNs, {});
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
- tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs);
+ tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs, &buckets);
tracker.noteStart("2:maps", true, eventStartTimeNs + 2 * bucketSizeNs, key1);
EXPECT_EQ((long long)(bucketStartTimeNs + 2 * bucketSizeNs), tracker.mLastStartTime);
- EXPECT_EQ(2u, buckets.size());
- EXPECT_EQ(bucketSizeNs - 1, buckets[0].mDuration);
- EXPECT_EQ(bucketSizeNs, buckets[1].mDuration);
+ EXPECT_EQ(2u, buckets[eventKey].size());
+ EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
+ EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
tracker.noteStop("2:maps", eventStartTimeNs + 2 * bucketSizeNs + 10, false);
tracker.noteStop("2:maps", eventStartTimeNs + 2 * bucketSizeNs + 12, false);
- tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 12);
- EXPECT_EQ(2u, buckets.size());
- EXPECT_EQ(bucketSizeNs - 1, buckets[0].mDuration);
- EXPECT_EQ(bucketSizeNs, buckets[1].mDuration);
+ tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 12, &buckets);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(2u, buckets[eventKey].size());
+ EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
+ EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
}
TEST(OringDurationTrackerTest, TestDurationConditionChange) {
@@ -157,15 +163,15 @@
EXPECT_CALL(*wizard, query(_, key1)) // #4
.WillOnce(Return(ConditionState::kFalse));
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t durationTimeNs = 2 * 1000;
- OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, false, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
+ bucketStartTimeNs, bucketSizeNs, {});
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
@@ -173,9 +179,10 @@
tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs, false);
- tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(5ULL, buckets[0].mDuration);
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(1u, buckets[eventKey].size());
+ EXPECT_EQ(5ULL, buckets[eventKey][0].mDuration);
}
TEST(OringDurationTrackerTest, TestDurationConditionChange2) {
@@ -189,15 +196,15 @@
.WillOnce(Return(ConditionState::kFalse))
.WillOnce(Return(ConditionState::kTrue));
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t durationTimeNs = 2 * 1000;
- OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, false, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
+ bucketStartTimeNs, bucketSizeNs, {});
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
// condition to false; record duration 5n
@@ -207,9 +214,10 @@
// 2nd duration: 1000ns
tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs, false);
- tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(1005ULL, buckets[0].mDuration);
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(1u, buckets[eventKey].size());
+ EXPECT_EQ(1005ULL, buckets[eventKey][0].mDuration);
}
TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) {
@@ -221,14 +229,14 @@
EXPECT_CALL(*wizard, query(_, key1)) // #4
.WillOnce(Return(ConditionState::kFalse));
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+ bucketSizeNs, {});
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
tracker.noteStart("2:maps", true, eventStartTimeNs + 2, key1);
@@ -239,9 +247,10 @@
tracker.noteStop("2:maps", eventStartTimeNs + 2003, false);
- tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(15ULL, buckets[0].mDuration);
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(1u, buckets[eventKey].size());
+ EXPECT_EQ(15ULL, buckets[eventKey][0].mDuration);
}
TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
@@ -252,7 +261,7 @@
alert.set_number_of_buckets(2);
alert.set_refractory_period_secs(1);
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
key1["APP_BACKGROUND"] = "1:maps|";
@@ -260,9 +269,9 @@
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
- sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, bucketSizeNs);
- OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs,
- bucketSizeNs, {anomalyTracker}, buckets);
+ sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
+ OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+ bucketSizeNs, {anomalyTracker});
// Nothing in the past bucket.
tracker.noteStart("", true, eventStartTimeNs, key1);
@@ -270,7 +279,7 @@
tracker.predictAnomalyTimestampNs(*anomalyTracker, eventStartTimeNs));
tracker.noteStop("", eventStartTimeNs + 3, false);
- EXPECT_EQ(0u, buckets.size());
+ EXPECT_EQ(0u, buckets[eventKey].size());
uint64_t event1StartTimeNs = eventStartTimeNs + 10;
tracker.noteStart("1", true, event1StartTimeNs, key1);
@@ -279,11 +288,13 @@
tracker.predictAnomalyTimestampNs(*anomalyTracker, event1StartTimeNs));
uint64_t event1StopTimeNs = eventStartTimeNs + bucketSizeNs + 10;
- tracker.flushIfNeeded(event1StopTimeNs);
+ tracker.flushIfNeeded(event1StopTimeNs, &buckets);
tracker.noteStop("1", event1StopTimeNs, false);
- EXPECT_EQ(1u, buckets.size());
+
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(1u, buckets[eventKey].size());
EXPECT_EQ(3ULL + bucketStartTimeNs + bucketSizeNs - eventStartTimeNs - 10,
- buckets[0].mDuration);
+ buckets[eventKey][0].mDuration);
const int64_t bucket0Duration = 3ULL + bucketStartTimeNs + bucketSizeNs - eventStartTimeNs - 10;
const int64_t bucket1Duration = eventStartTimeNs + 10 - bucketStartTimeNs;
@@ -312,7 +323,7 @@
alert.set_number_of_buckets(2);
alert.set_refractory_period_secs(1);
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
key1["APP_BACKGROUND"] = "1:maps|";
@@ -320,9 +331,9 @@
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
- sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, bucketSizeNs);
- OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true /*nesting*/,
- bucketStartTimeNs, bucketSizeNs, {anomalyTracker}, buckets);
+ sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
+ OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true /*nesting*/,
+ bucketStartTimeNs, bucketSizeNs, {anomalyTracker});
tracker.noteStart("", true, eventStartTimeNs, key1);
tracker.noteStop("", eventStartTimeNs + 10, false);
@@ -336,7 +347,7 @@
EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
EXPECT_EQ((long long)(51ULL * NS_PER_SEC),
(long long)(anomalyTracker->mAlarms.begin()->second->timestampSec * NS_PER_SEC));
- tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 25);
+ tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 25, &buckets);
tracker.noteStop("", eventStartTimeNs + 2 * bucketSizeNs + 25, false);
EXPECT_EQ(anomalyTracker->getSumOverPastBuckets("event"), (long long)(bucketSizeNs));
EXPECT_EQ((long long)(eventStartTimeNs + 2 * bucketSizeNs + 25),
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 9d78466..d320697 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -282,7 +282,7 @@
EXPECT_EQ(20, curInterval.raw.back().first);
EXPECT_EQ(0UL, valueProducer.mNextSlicedBucket.size());
- valueProducer.flushIfNeeded(bucket3StartTimeNs);
+ valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
EXPECT_EQ(30, valueProducer.mPastBuckets.begin()->second.back().mValue);
diff --git a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
index 5b59c21..fe3d86d 100644
--- a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
+++ b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
@@ -110,113 +110,7 @@
log.getEventMetrics();
for (StatsLog.EventMetricData event : eventMetricDataWrapper.getDataList()) {
sb.append(getDateStr(event.getTimestampNanos())).append(": ");
- switch (event.getAtom().getPushedCase()) {
- case SETTING_CHANGED:
- sb.append("SETTING_CHANGED\n");
- break;
- case SYNC_STATE_CHANGED:
- sb.append("SYNC_STATE_CHANGED\n");
- break;
- case AUDIO_STATE_CHANGED:
- sb.append("AUDIO_STATE_CHANGED\n");
- break;
- case CAMERA_STATE_CHANGED:
- sb.append("CAMERA_STATE_CHANGED\n");
- break;
- case ISOLATED_UID_CHANGED:
- sb.append("ISOLATED_UID_CHANGED\n");
- break;
- case SCREEN_STATE_CHANGED:
- sb.append("SCREEN_STATE_CHANGED\n");
- break;
- case SENSOR_STATE_CHANGED:
- sb.append("SENSOR_STATE_CHANGED\n");
- break;
- case BATTERY_LEVEL_CHANGED:
- sb.append("BATTERY_LEVEL_CHANGED\n");
- break;
- case PLUGGED_STATE_CHANGED:
- sb.append("PLUGGED_STATE_CHANGED\n");
- break;
- case WAKEUP_ALARM_OCCURRED:
- sb.append("WAKEUP_ALARM_OCCURRED\n");
- break;
- case BLE_SCAN_STATE_CHANGED:
- sb.append("BLE_SCAN_STATE_CHANGED\n");
- break;
- case CHARGING_STATE_CHANGED:
- sb.append("CHARGING_STATE_CHANGED\n");
- break;
- case GPS_SCAN_STATE_CHANGED:
- sb.append("GPS_SCAN_STATE_CHANGED\n");
- break;
- case KERNEL_WAKEUP_REPORTED:
- sb.append("KERNEL_WAKEUP_REPORTED\n");
- break;
- case WAKELOCK_STATE_CHANGED:
- sb.append("WAKELOCK_STATE_CHANGED\n");
- break;
- case WIFI_LOCK_STATE_CHANGED:
- sb.append("WIFI_LOCK_STATE_CHANGED\n");
- break;
- case WIFI_SCAN_STATE_CHANGED:
- sb.append("WIFI_SCAN_STATE_CHANGED\n");
- break;
- case BLE_SCAN_RESULT_RECEIVED:
- sb.append("BLE_SCAN_RESULT_RECEIVED\n");
- break;
- case DEVICE_ON_STATUS_CHANGED:
- sb.append("DEVICE_ON_STATUS_CHANGED\n");
- break;
- case FLASHLIGHT_STATE_CHANGED:
- sb.append("FLASHLIGHT_STATE_CHANGED\n");
- break;
- case SCREEN_BRIGHTNESS_CHANGED:
- sb.append("SCREEN_BRIGHTNESS_CHANGED\n");
- break;
- case UID_PROCESS_STATE_CHANGED:
- sb.append("UID_PROCESS_STATE_CHANGED\n");
- break;
- case UID_WAKELOCK_STATE_CHANGED:
- sb.append("UID_WAKELOCK_STATE_CHANGED\n");
- break;
- case DEVICE_TEMPERATURE_REPORTED:
- sb.append("DEVICE_TEMPERATURE_REPORTED\n");
- break;
- case SCHEDULED_JOB_STATE_CHANGED:
- sb.append("SCHEDULED_JOB_STATE_CHANGED\n");
- break;
- case MEDIA_CODEC_ACTIVITY_CHANGED:
- sb.append("MEDIA_CODEC_ACTIVITY_CHANGED\n");
- break;
- case WIFI_SIGNAL_STRENGTH_CHANGED:
- sb.append("WIFI_SIGNAL_STRENGTH_CHANGED\n");
- break;
- case PHONE_SIGNAL_STRENGTH_CHANGED:
- sb.append("PHONE_SIGNAL_STRENGTH_CHANGED\n");
- break;
- case DEVICE_IDLE_MODE_STATE_CHANGED:
- sb.append("DEVICE_IDLE_MODE_STATE_CHANGED\n");
- break;
- case BATTERY_SAVER_MODE_STATE_CHANGED:
- sb.append("BATTERY_SAVER_MODE_STATE_CHANGED\n");
- break;
- case PROCESS_LIFE_CYCLE_STATE_CHANGED:
- sb.append("PROCESS_LIFE_CYCLE_STATE_CHANGED\n");
- break;
- case ACTIVITY_FOREGROUND_STATE_CHANGED:
- sb.append("ACTIVITY_FOREGROUND_STATE_CHANGED\n");
- break;
- case BLE_UNOPTIMIZED_SCAN_STATE_CHANGED:
- sb.append("BLE_UNOPTIMIZED_SCAN_STATE_CHANGED\n");
- break;
- case LONG_PARTIAL_WAKELOCK_STATE_CHANGED:
- sb.append("LONG_PARTIAL_WAKELOCK_STATE_CHANGED\n");
- break;
- case PUSHED_NOT_SET:
- sb.append("PUSHED_NOT_SET\n");
- break;
- }
+ sb.append(event.getAtom().getPushedCase().toString()).append("\n");
}
}
diff --git a/cmds/statsd/tools/loadtest/Android.mk b/cmds/statsd/tools/loadtest/Android.mk
new file mode 100644
index 0000000..f3f0a7c
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/Android.mk
@@ -0,0 +1,35 @@
+# 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.
+#
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SRC_FILES += ../../src/stats_log.proto \
+ ../../src/atoms_copy.proto \
+ ../../src/statsd_config.proto
+
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/../../src/
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := lite-static
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := StatsdLoadtest
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_DEX_PREOPT := false
+include $(BUILD_PACKAGE)
diff --git a/cmds/statsd/tools/loadtest/AndroidManifest.xml b/cmds/statsd/tools/loadtest/AndroidManifest.xml
new file mode 100644
index 0000000..2bf8ca9
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.statsd.loadtest"
+ android:sharedUserId="android.uid.system"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-permission android:name="android.permission.DUMP" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name" >
+ <activity
+ android:name=".LoadtestActivity"
+ android:label="@string/app_name"
+ android:launchMode="singleTop" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <receiver android:name=".LoadtestActivity$PusherAlarmReceiver" />
+ <receiver android:name=".LoadtestActivity$StopperAlarmReceiver"/>
+ <receiver android:name=".PerfData$PerfAlarmReceiver"/>
+ </application>
+</manifest>
diff --git a/cmds/statsd/tools/loadtest/res/drawable-hdpi/ic_launcher.png b/cmds/statsd/tools/loadtest/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..55621cc
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/drawable-mdpi/ic_launcher.png b/cmds/statsd/tools/loadtest/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..11ec206
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/drawable-xhdpi/ic_launcher.png b/cmds/statsd/tools/loadtest/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..7c02b78
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/drawable-xxhdpi/ic_launcher.png b/cmds/statsd/tools/loadtest/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..915d914
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml b/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml
new file mode 100644
index 0000000..1e28f67
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2007, 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.
+*/
+-->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <LinearLayout
+ android:id="@+id/outside"
+ android:clickable="true"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:gravity="center"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginRight="10dp"
+ android:layout_marginLeft="10dp"
+ android:orientation="vertical">
+ <requestFocus />
+
+ <LinearLayout
+ android:gravity="center"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+ <TextView
+ android:textSize="30dp"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/replication_label" />
+ <EditText
+ android:id="@+id/replication"
+ android:inputType="number"
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxLength="3"
+ android:text="@integer/replication_default"
+ android:textSize="30dp"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:gravity="center"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+ <TextView
+ android:textSize="30dp"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/bucket_label" />
+ <EditText
+ android:id="@+id/bucket"
+ android:inputType="number"
+ android:layout_weight="1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:maxLength="3"
+ android:text="@integer/bucket_default"
+ android:textSize="30dp"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:gravity="center"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+ <TextView
+ android:textSize="30dp"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/period_label" />
+ <EditText
+ android:id="@+id/period"
+ android:inputType="number"
+ android:layout_weight="1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:maxLength="3"
+ android:text="@integer/period_default"
+ android:textSize="30dp"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:gravity="center"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+ <TextView
+ android:textSize="30dp"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/burst_label" />
+ <EditText
+ android:id="@+id/burst"
+ android:inputType="number"
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxLength="2"
+ android:text="@integer/burst_default"
+ android:textSize="30dp"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:gravity="center"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+ <TextView
+ android:textSize="30dp"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/duration_label" />
+ <EditText
+ android:id="@+id/duration"
+ android:inputType="number"
+ android:layout_weight="1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:maxLength="4"
+ android:text="@integer/duration_default"
+ android:textSize="30dp"/>
+ </LinearLayout>
+ <CheckBox
+ android:id="@+id/placebo"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/placebo"
+ android:checked="false" />
+
+ <Space
+ android:layout_width="1dp"
+ android:layout_height="30dp"/>
+
+ <Button
+ android:id="@+id/start_stop"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="#ffff0000"
+ android:text="@string/start"
+ android:textSize="50dp"/>
+
+ <Space
+ android:layout_width="1dp"
+ android:layout_height="30dp"/>
+
+ <Button
+ android:id="@+id/display_output"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/display_output"
+ android:textSize="30dp"/>
+
+ <Space
+ android:layout_width="1dp"
+ android:layout_height="30dp"/>
+
+ <TextView
+ android:id="@+id/report_text"
+ android:gravity="center"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
+
+</ScrollView>
diff --git a/cmds/statsd/tools/loadtest/res/raw/loadtest_config b/cmds/statsd/tools/loadtest/res/raw/loadtest_config
new file mode 100755
index 0000000..7822367
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/res/raw/loadtest_config
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/values/integers.xml b/cmds/statsd/tools/loadtest/res/values/integers.xml
new file mode 100644
index 0000000..76b5692
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/res/values/integers.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <integer name="bucket_default">10</integer>
+ <integer name="burst_default">1</integer>
+ <integer name="period_default">2</integer>
+ <integer name="replication_default">1</integer>
+ <integer name="duration_default">240</integer>
+</resources>
diff --git a/cmds/statsd/tools/loadtest/res/values/strings.xml b/cmds/statsd/tools/loadtest/res/values/strings.xml
new file mode 100644
index 0000000..cb38298
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/res/values/strings.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <string name="app_name">Statsd Loadtest</string>
+ <string name="bucket_label">bucket size (mins): </string>
+ <string name="burst_label">burst: </string>
+ <string name="display_output">Show metrics data</string>
+ <string name="placebo">placebo</string>
+ <string name="period_label">logging period (secs): </string>
+ <string name="replication_label">metric replication: </string>
+ <string name="duration_label">test duration (mins): </string>
+ <string name="start">  Start  </string>
+ <string name="stop">  Stop  </string>
+
+</resources>
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryDataRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryDataRecorder.java
new file mode 100644
index 0000000..d2ff892
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryDataRecorder.java
@@ -0,0 +1,53 @@
+/*
+ * 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.statsd.loadtest;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.Log;
+import java.text.ParseException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class BatteryDataRecorder extends PerfDataRecorder {
+ private static final String TAG = "loadtest.BatteryDataRecorder";
+ private static final String DUMP_FILENAME = TAG + "_dump.tmp";
+
+ public BatteryDataRecorder(boolean placebo, int replication, long bucketMins, long periodSecs,
+ int burst) {
+ super(placebo, replication, bucketMins, periodSecs, burst);
+ }
+
+ @Override
+ public void startRecording(Context context) {
+ // Reset batterystats.
+ runDumpsysStats(context, DUMP_FILENAME, "batterystats", "--reset");
+ }
+
+ @Override
+ public void onAlarm(Context context) {
+ // Nothing to do as for battery, the whole data is in the final dumpsys call.
+ }
+
+ @Override
+ public void stopRecording(Context context) {
+ StringBuilder sb = new StringBuilder();
+ // Don't use --checkin.
+ runDumpsysStats(context, DUMP_FILENAME, "batterystats");
+ readDumpData(context, DUMP_FILENAME, new BatteryStatsParser(), sb);
+ writeData(context, "battery_", "time,battery_level", sb);
+ }
+}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryStatsParser.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryStatsParser.java
new file mode 100644
index 0000000..203d97a
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryStatsParser.java
@@ -0,0 +1,113 @@
+/*
+ * 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.statsd.loadtest;
+
+import android.annotation.Nullable;
+import android.util.Log;
+import java.text.ParseException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class BatteryStatsParser implements PerfParser {
+
+ private static final Pattern LINE_PATTERN =
+ Pattern.compile("\\s*\\+*(\\S*)\\s\\(\\d+\\)\\s(\\d\\d\\d)\\s.*");
+ private static final Pattern TIME_PATTERN =
+ Pattern.compile("(\\d+)?(h)?(\\d+)?(m)?(\\d+)?(s)?(\\d+)?(ms)?");
+ private static final String TAG = "loadtest.BatteryStatsParser";
+
+ private boolean mHistoryStarted;
+ private boolean mHistoryEnded;
+
+ public BatteryStatsParser() {
+ }
+
+ @Override
+ @Nullable
+ public String parseLine(String line) {
+ if (mHistoryEnded) {
+ return null;
+ }
+ if (!mHistoryStarted) {
+ if (line.contains("Battery History")) {
+ mHistoryStarted = true;
+ }
+ return null;
+ }
+ if (line.isEmpty()) {
+ mHistoryEnded = true;
+ return null;
+ }
+ Matcher lineMatcher = LINE_PATTERN.matcher(line);
+ if (lineMatcher.find() && lineMatcher.group(1) != null && lineMatcher.group(2) != null) {
+ if (lineMatcher.group(1).equals("0")) {
+ return "0," + lineMatcher.group(2) + "\n";
+ } else {
+ Matcher timeMatcher = TIME_PATTERN.matcher(lineMatcher.group(1));
+ if (timeMatcher.find()) {
+ Long time = getTime(lineMatcher.group(1));
+ if (time != null) {
+ return time + "," + lineMatcher.group(2) + "\n";
+ } else {
+ return null; // bad time
+ }
+ } else {
+ return null; // bad or no time
+ }
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private Long getTime(String group) {
+ if ("0".equals(group)) {
+ return 0L;
+ }
+ Matcher timeMatcher = TIME_PATTERN.matcher(group);
+ if (!timeMatcher.find()) {
+ return null;
+ }
+
+ // Get rid of "ms".
+ String[] matches = group.split("ms", -1);
+ if (matches.length > 1) {
+ group = matches[0];
+ }
+
+ long time = 0L;
+ matches = group.split("h");
+ if (matches.length > 1) {
+ time += Long.parseLong(matches[0]) * 60 * 60 * 1000; // hours
+ group = matches[1];
+ }
+ matches = group.split("m");
+ if (matches.length > 1) {
+ time += Long.parseLong(matches[0]) * 60 * 1000; // minutes
+ group = matches[1];
+ }
+ matches = group.split("s");
+ if (matches.length > 1) {
+ time += Long.parseLong(matches[0]) * 1000; // seconds
+ group = matches[1];
+ }
+
+ if (!group.isEmpty()) {
+ time += Long.parseLong(group); // milliseconds
+ }
+ return time;
+ }
+}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
new file mode 100644
index 0000000..0d890fb
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
@@ -0,0 +1,299 @@
+/*
+ * 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.statsd.loadtest;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.Log;
+
+import com.android.internal.os.StatsdConfigProto.Bucket;
+import com.android.internal.os.StatsdConfigProto.Predicate;
+import com.android.internal.os.StatsdConfigProto.CountMetric;
+import com.android.internal.os.StatsdConfigProto.DurationMetric;
+import com.android.internal.os.StatsdConfigProto.MetricConditionLink;
+import com.android.internal.os.StatsdConfigProto.EventMetric;
+import com.android.internal.os.StatsdConfigProto.GaugeMetric;
+import com.android.internal.os.StatsdConfigProto.ValueMetric;
+import com.android.internal.os.StatsdConfigProto.KeyMatcher;
+import com.android.internal.os.StatsdConfigProto.KeyValueMatcher;
+import com.android.internal.os.StatsdConfigProto.AtomMatcher;
+import com.android.internal.os.StatsdConfigProto.SimplePredicate;
+import com.android.internal.os.StatsdConfigProto.StatsdConfig;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Creates StatsdConfig protos for loadtesting.
+ */
+public class ConfigFactory {
+ public static final String CONFIG_NAME = "LOADTEST";
+
+ private static final String TAG = "loadtest.ConfigFactory";
+
+ private final StatsdConfig mTemplate;
+
+ public ConfigFactory(Context context) {
+ // Read the config template from the resoures.
+ Resources res = context.getResources();
+ byte[] template = null;
+ StatsdConfig templateProto = null;
+ try {
+ InputStream inputStream = res.openRawResource(R.raw.loadtest_config);
+ template = new byte[inputStream.available()];
+ inputStream.read(template);
+ templateProto = StatsdConfig.parseFrom(template);
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to read or parse loadtest config template. Using an empty config.");
+ }
+ mTemplate = templateProto == null ? StatsdConfig.newBuilder().build() : templateProto;
+
+ Log.d(TAG, "Loadtest template config: " + mTemplate);
+ }
+
+ /**
+ * Generates a config.
+ *
+ * All configs are based on the same template.
+ * That template is designed to make the most use of the set of atoms that {@code SequencePusher}
+ * pushes, and to exercise as many of the metrics features as possible.
+ * Furthermore, by passing a replication factor to this method, one can artificially inflate
+ * the number of metrics in the config. One can also adjust the bucket size for aggregate
+ * metrics.
+ *
+ * @param replication The number of times each metric is replicated in the config.
+ * If the config template has n metrics, the generated config will have n * replication
+ * ones
+ * @param bucketMillis The bucket size, in milliseconds, for aggregate metrics
+ * @param placebo If true, only return an empty config
+ * @return The serialized config
+ */
+ public byte[] getConfig(int replication, long bucketMillis, boolean placebo) {
+ StatsdConfig.Builder config = StatsdConfig.newBuilder()
+ .setName(CONFIG_NAME);
+ if (placebo) {
+ replication = 0; // Config will be empty, aside from a name.
+ }
+ int numMetrics = 0;
+ for (int i = 0; i < replication; i++) {
+ // metrics
+ for (EventMetric metric : mTemplate.getEventMetricList()) {
+ addEventMetric(metric, i, config);
+ numMetrics++;
+ }
+ for (CountMetric metric : mTemplate.getCountMetricList()) {
+ addCountMetric(metric, i, bucketMillis, config);
+ numMetrics++;
+ }
+ for (DurationMetric metric : mTemplate.getDurationMetricList()) {
+ addDurationMetric(metric, i, bucketMillis, config);
+ numMetrics++;
+ }
+ for (GaugeMetric metric : mTemplate.getGaugeMetricList()) {
+ addGaugeMetric(metric, i, bucketMillis, config);
+ numMetrics++;
+ }
+ for (ValueMetric metric : mTemplate.getValueMetricList()) {
+ addValueMetric(metric, i, bucketMillis, config);
+ numMetrics++;
+ }
+ // predicates
+ for (Predicate predicate : mTemplate.getPredicateList()) {
+ addPredicate(predicate, i, config);
+ }
+ // matchers
+ for (AtomMatcher matcher : mTemplate.getAtomMatcherList()) {
+ addMatcher(matcher, i, config);
+ }
+ }
+
+ Log.d(TAG, "Loadtest config is : " + config.build());
+ Log.d(TAG, "Generated config has " + numMetrics + " metrics");
+
+ return config.build().toByteArray();
+ }
+
+ /**
+ * Creates {@link MetricConditionLink}s that are identical to the one passed to this method,
+ * except that the names are appended with the provided suffix.
+ */
+ private List<MetricConditionLink> getLinks(
+ List<MetricConditionLink> links, int suffix) {
+ List<MetricConditionLink> newLinks = new ArrayList();
+ for (MetricConditionLink link : links) {
+ newLinks.add(link.toBuilder()
+ .setCondition(link.getCondition() + suffix)
+ .build());
+ }
+ return newLinks;
+ }
+
+ /**
+ * Creates an {@link EventMetric} based on the template. Makes sure that all names are appended
+ * with the provided suffix. Then adds that metric to the config.
+ */
+ private void addEventMetric(EventMetric template, int suffix, StatsdConfig.Builder config) {
+ EventMetric.Builder metric = template.toBuilder()
+ .setName(template.getName() + suffix)
+ .setWhat(template.getWhat() + suffix);
+ if (template.hasCondition()) {
+ metric.setCondition(template.getCondition() + suffix);
+ }
+ if (template.getLinksCount() > 0) {
+ List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
+ metric.clearLinks();
+ metric.addAllLinks(links);
+ }
+ config.addEventMetric(metric);
+ }
+
+ private Bucket getBucket(long bucketMillis) {
+ return Bucket.newBuilder()
+ .setBucketSizeMillis(bucketMillis)
+ .build();
+ }
+
+ /**
+ * Creates a {@link CountMetric} based on the template. Makes sure that all names are appended
+ * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
+ */
+ private void addCountMetric(CountMetric template, int suffix, long bucketMillis,
+ StatsdConfig.Builder config) {
+ CountMetric.Builder metric = template.toBuilder()
+ .setName(template.getName() + suffix)
+ .setWhat(template.getWhat() + suffix);
+ if (template.hasCondition()) {
+ metric.setCondition(template.getCondition() + suffix);
+ }
+ if (template.getLinksCount() > 0) {
+ List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
+ metric.clearLinks();
+ metric.addAllLinks(links);
+ }
+ metric.setBucket(getBucket(bucketMillis));
+ config.addCountMetric(metric);
+ }
+
+ /**
+ * Creates a {@link DurationMetric} based on the template. Makes sure that all names are appended
+ * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
+ */
+ private void addDurationMetric(DurationMetric template, int suffix, long bucketMillis,
+ StatsdConfig.Builder config) {
+ DurationMetric.Builder metric = template.toBuilder()
+ .setName(template.getName() + suffix)
+ .setWhat(template.getWhat() + suffix);
+ if (template.hasCondition()) {
+ metric.setCondition(template.getCondition() + suffix);
+ }
+ if (template.getLinksCount() > 0) {
+ List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
+ metric.clearLinks();
+ metric.addAllLinks(links);
+ }
+ metric.setBucket(getBucket(bucketMillis));
+ config.addDurationMetric(metric);
+ }
+
+ /**
+ * Creates a {@link GaugeMetric} based on the template. Makes sure that all names are appended
+ * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
+ */
+ private void addGaugeMetric(GaugeMetric template, int suffix, long bucketMillis,
+ StatsdConfig.Builder config) {
+ GaugeMetric.Builder metric = template.toBuilder()
+ .setName(template.getName() + suffix)
+ .setWhat(template.getWhat() + suffix);
+ if (template.hasCondition()) {
+ metric.setCondition(template.getCondition() + suffix);
+ }
+ if (template.getLinksCount() > 0) {
+ List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
+ metric.clearLinks();
+ metric.addAllLinks(links);
+ }
+ metric.setBucket(getBucket(bucketMillis));
+ config.addGaugeMetric(metric);
+ }
+
+ /**
+ * Creates a {@link ValueMetric} based on the template. Makes sure that all names are appended
+ * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
+ */
+ private void addValueMetric(ValueMetric template, int suffix, long bucketMillis,
+ StatsdConfig.Builder config) {
+ ValueMetric.Builder metric = template.toBuilder()
+ .setName(template.getName() + suffix)
+ .setWhat(template.getWhat() + suffix);
+ if (template.hasCondition()) {
+ metric.setCondition(template.getCondition() + suffix);
+ }
+ if (template.getLinksCount() > 0) {
+ List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
+ metric.clearLinks();
+ metric.addAllLinks(links);
+ }
+ metric.setBucket(getBucket(bucketMillis));
+ config.addValueMetric(metric);
+ }
+
+ /**
+ * Creates a {@link Predicate} based on the template. Makes sure that all names
+ * are appended with the provided suffix. Then adds that predicate to the config.
+ */
+ private void addPredicate(Predicate template, int suffix, StatsdConfig.Builder config) {
+ Predicate.Builder predicate = template.toBuilder()
+ .setName(template.getName() + suffix);
+ if (template.hasCombination()) {
+ Predicate.Combination.Builder cb = template.getCombination().toBuilder()
+ .clearPredicate();
+ for (String child : template.getCombination().getPredicateList()) {
+ cb.addPredicate(child + suffix);
+ }
+ predicate.setCombination(cb.build());
+ }
+ if (template.hasSimplePredicate()) {
+ SimplePredicate.Builder sc = template.getSimplePredicate().toBuilder()
+ .setStart(template.getSimplePredicate().getStart() + suffix)
+ .setStop(template.getSimplePredicate().getStop() + suffix);
+ if (template.getSimplePredicate().hasStopAll()) {
+ sc.setStopAll(template.getSimplePredicate().getStopAll() + suffix);
+ }
+ predicate.setSimplePredicate(sc.build());
+ }
+ config.addPredicate(predicate);
+ }
+
+ /**
+ * Creates a {@link AtomMatcher} based on the template. Makes sure that all names
+ * are appended with the provided suffix. Then adds that matcher to the config.
+ */
+ private void addMatcher(AtomMatcher template, int suffix, StatsdConfig.Builder config) {
+ AtomMatcher.Builder matcher = template.toBuilder()
+ .setName(template.getName() + suffix);
+ if (template.hasCombination()) {
+ AtomMatcher.Combination.Builder cb = template.getCombination().toBuilder()
+ .clearMatcher();
+ for (String child : template.getCombination().getMatcherList()) {
+ cb.addMatcher(child + suffix);
+ }
+ matcher.setCombination(cb);
+ }
+ config.addAtomMatcher(matcher);
+ }
+}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
new file mode 100644
index 0000000..5e8f26d
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
@@ -0,0 +1,247 @@
+/*
+ * 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.statsd.loadtest;
+
+import android.text.format.DateFormat;
+
+import com.android.os.StatsLog;
+
+import java.util.List;
+
+public class DisplayProtoUtils {
+ public static void displayLogReport(StringBuilder sb, StatsLog.ConfigMetricsReportList reports) {
+ sb.append("ConfigKey: ");
+ if (reports.hasConfigKey()) {
+ com.android.os.StatsLog.ConfigMetricsReportList.ConfigKey key = reports.getConfigKey();
+ sb.append("\tuid: ").append(key.getUid()).append(" name: ").append(key.getName())
+ .append("\n");
+ }
+
+ for (StatsLog.ConfigMetricsReport report : reports.getReportsList()) {
+ sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
+ for (StatsLog.StatsLogReport log : report.getMetricsList()) {
+ sb.append("\n\n");
+ sb.append("metric id: ").append(log.getMetricName()).append("\n");
+ sb.append("start time:").append(getDateStr(log.getStartReportNanos())).append("\n");
+ sb.append("end time:").append(getDateStr(log.getEndReportNanos())).append("\n");
+
+ switch (log.getDataCase()) {
+ case DURATION_METRICS:
+ sb.append("Duration metric data\n");
+ displayDurationMetricData(sb, log);
+ break;
+ case EVENT_METRICS:
+ sb.append("Event metric data\n");
+ displayEventMetricData(sb, log);
+ break;
+ case COUNT_METRICS:
+ sb.append("Count metric data\n");
+ displayCountMetricData(sb, log);
+ break;
+ case GAUGE_METRICS:
+ sb.append("Gauge metric data\n");
+ displayGaugeMetricData(sb, log);
+ break;
+ case VALUE_METRICS:
+ sb.append("Value metric data\n");
+ displayValueMetricData(sb, log);
+ break;
+ case DATA_NOT_SET:
+ sb.append("No metric data\n");
+ break;
+ }
+ }
+ }
+ }
+
+ public static String getDateStr(long nanoSec) {
+ return DateFormat.format("dd/MM hh:mm:ss", nanoSec/1000000).toString();
+ }
+
+ private static void displayDimension(StringBuilder sb, List<StatsLog.KeyValuePair> pairs) {
+ for (com.android.os.StatsLog.KeyValuePair kv : pairs) {
+ sb.append(kv.getKey()).append(":");
+ if (kv.hasValueBool()) {
+ sb.append(kv.getValueBool());
+ } else if (kv.hasValueFloat()) {
+ sb.append(kv.getValueFloat());
+ } else if (kv.hasValueInt()) {
+ sb.append(kv.getValueInt());
+ } else if (kv.hasValueStr()) {
+ sb.append(kv.getValueStr());
+ }
+ sb.append(" ");
+ }
+ }
+
+ public static void displayDurationMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
+ StatsLog.StatsLogReport.DurationMetricDataWrapper durationMetricDataWrapper
+ = log.getDurationMetrics();
+ sb.append("Dimension size: ").append(durationMetricDataWrapper.getDataCount()).append("\n");
+ for (StatsLog.DurationMetricData duration : durationMetricDataWrapper.getDataList()) {
+ sb.append("dimension: ");
+ displayDimension(sb, duration.getDimensionList());
+ sb.append("\n");
+
+ for (StatsLog.DurationBucketInfo info : duration.getBucketInfoList()) {
+ sb.append("\t[").append(getDateStr(info.getStartBucketNanos())).append("-")
+ .append(getDateStr(info.getEndBucketNanos())).append("] -> ")
+ .append(info.getDurationNanos()).append(" ns\n");
+ }
+ }
+ }
+
+ public static void displayEventMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
+ sb.append("Contains ").append(log.getEventMetrics().getDataCount()).append(" events\n");
+ StatsLog.StatsLogReport.EventMetricDataWrapper eventMetricDataWrapper =
+ log.getEventMetrics();
+ for (StatsLog.EventMetricData event : eventMetricDataWrapper.getDataList()) {
+ sb.append(getDateStr(event.getTimestampNanos())).append(": ");
+ switch (event.getAtom().getPushedCase()) {
+ case SETTING_CHANGED:
+ sb.append("SETTING_CHANGED\n");
+ break;
+ case SYNC_STATE_CHANGED:
+ sb.append("SYNC_STATE_CHANGED\n");
+ break;
+ case AUDIO_STATE_CHANGED:
+ sb.append("AUDIO_STATE_CHANGED\n");
+ break;
+ case CAMERA_STATE_CHANGED:
+ sb.append("CAMERA_STATE_CHANGED\n");
+ break;
+ case ISOLATED_UID_CHANGED:
+ sb.append("ISOLATED_UID_CHANGED\n");
+ break;
+ case SCREEN_STATE_CHANGED:
+ sb.append("SCREEN_STATE_CHANGED\n");
+ break;
+ case SENSOR_STATE_CHANGED:
+ sb.append("SENSOR_STATE_CHANGED\n");
+ break;
+ case BATTERY_LEVEL_CHANGED:
+ sb.append("BATTERY_LEVEL_CHANGED\n");
+ break;
+ case PLUGGED_STATE_CHANGED:
+ sb.append("PLUGGED_STATE_CHANGED\n");
+ break;
+ case WAKEUP_ALARM_OCCURRED:
+ sb.append("WAKEUP_ALARM_OCCURRED\n");
+ break;
+ case BLE_SCAN_STATE_CHANGED:
+ sb.append("BLE_SCAN_STATE_CHANGED\n");
+ break;
+ case CHARGING_STATE_CHANGED:
+ sb.append("CHARGING_STATE_CHANGED\n");
+ break;
+ case GPS_SCAN_STATE_CHANGED:
+ sb.append("GPS_SCAN_STATE_CHANGED\n");
+ break;
+ case KERNEL_WAKEUP_REPORTED:
+ sb.append("KERNEL_WAKEUP_REPORTED\n");
+ break;
+ case WAKELOCK_STATE_CHANGED:
+ sb.append("WAKELOCK_STATE_CHANGED\n");
+ break;
+ case WIFI_LOCK_STATE_CHANGED:
+ sb.append("WIFI_LOCK_STATE_CHANGED\n");
+ break;
+ case WIFI_SCAN_STATE_CHANGED:
+ sb.append("WIFI_SCAN_STATE_CHANGED\n");
+ break;
+ case BLE_SCAN_RESULT_RECEIVED:
+ sb.append("BLE_SCAN_RESULT_RECEIVED\n");
+ break;
+ case DEVICE_ON_STATUS_CHANGED:
+ sb.append("DEVICE_ON_STATUS_CHANGED\n");
+ break;
+ case FLASHLIGHT_STATE_CHANGED:
+ sb.append("FLASHLIGHT_STATE_CHANGED\n");
+ break;
+ case SCREEN_BRIGHTNESS_CHANGED:
+ sb.append("SCREEN_BRIGHTNESS_CHANGED\n");
+ break;
+ case UID_PROCESS_STATE_CHANGED:
+ sb.append("UID_PROCESS_STATE_CHANGED\n");
+ break;
+ case UID_WAKELOCK_STATE_CHANGED:
+ sb.append("UID_WAKELOCK_STATE_CHANGED\n");
+ break;
+ case DEVICE_TEMPERATURE_REPORTED:
+ sb.append("DEVICE_TEMPERATURE_REPORTED\n");
+ break;
+ case SCHEDULED_JOB_STATE_CHANGED:
+ sb.append("SCHEDULED_JOB_STATE_CHANGED\n");
+ break;
+ case MEDIA_CODEC_ACTIVITY_CHANGED:
+ sb.append("MEDIA_CODEC_ACTIVITY_CHANGED\n");
+ break;
+ case WIFI_SIGNAL_STRENGTH_CHANGED:
+ sb.append("WIFI_SIGNAL_STRENGTH_CHANGED\n");
+ break;
+ case PHONE_SIGNAL_STRENGTH_CHANGED:
+ sb.append("PHONE_SIGNAL_STRENGTH_CHANGED\n");
+ break;
+ case DEVICE_IDLE_MODE_STATE_CHANGED:
+ sb.append("DEVICE_IDLE_MODE_STATE_CHANGED\n");
+ break;
+ case BATTERY_SAVER_MODE_STATE_CHANGED:
+ sb.append("BATTERY_SAVER_MODE_STATE_CHANGED\n");
+ break;
+ case PROCESS_LIFE_CYCLE_STATE_CHANGED:
+ sb.append("PROCESS_LIFE_CYCLE_STATE_CHANGED\n");
+ break;
+ case ACTIVITY_FOREGROUND_STATE_CHANGED:
+ sb.append("ACTIVITY_FOREGROUND_STATE_CHANGED\n");
+ break;
+ case BLE_UNOPTIMIZED_SCAN_STATE_CHANGED:
+ sb.append("BLE_UNOPTIMIZED_SCAN_STATE_CHANGED\n");
+ break;
+ case LONG_PARTIAL_WAKELOCK_STATE_CHANGED:
+ sb.append("LONG_PARTIAL_WAKELOCK_STATE_CHANGED\n");
+ break;
+ case PUSHED_NOT_SET:
+ sb.append("PUSHED_NOT_SET\n");
+ break;
+ }
+ }
+ }
+
+ public static void displayCountMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
+ StatsLog.StatsLogReport.CountMetricDataWrapper countMetricDataWrapper
+ = log.getCountMetrics();
+ sb.append("Dimension size: ").append(countMetricDataWrapper.getDataCount()).append("\n");
+ for (StatsLog.CountMetricData count : countMetricDataWrapper.getDataList()) {
+ sb.append("dimension: ");
+ displayDimension(sb, count.getDimensionList());
+ sb.append("\n");
+
+ for (StatsLog.CountBucketInfo info : count.getBucketInfoList()) {
+ sb.append("\t[").append(getDateStr(info.getStartBucketNanos())).append("-")
+ .append(getDateStr(info.getEndBucketNanos())).append("] -> ")
+ .append(info.getCount()).append("\n");
+ }
+ }
+ }
+
+ public static void displayGaugeMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
+ sb.append("Display me!");
+ }
+
+ public static void displayValueMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
+ sb.append("Display me!");
+ }
+}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
new file mode 100644
index 0000000..522dea6
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
@@ -0,0 +1,549 @@
+/*
+ * 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.statsd.loadtest;
+
+import android.app.Activity;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IStatsManager;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.util.StatsLog;
+import android.util.StatsManager;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+import android.view.MotionEvent;
+import android.view.View.OnFocusChangeListener;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+/**
+ * Runs a load test for statsd.
+ * How it works:
+ * <ul>
+ * <li> Sets up and pushes a custom config with metrics that exercise a large swath of code paths.
+ * <li> Periodically logs certain atoms into logd.
+ * <li> Impact on battery can be printed to logcat, or a bug report can be filed and analyzed
+ * in battery Historian.
+ * </ul>
+ * The load depends on how demanding the config is, as well as how frequently atoms are pushsed
+ * to logd. Those are all controlled by 4 adjustable parameters:
+ * <ul>
+ * <li> The 'replication' parameter artificially multiplies the number of metrics in the config.
+ * <li> The bucket size controls the time-bucketing the aggregate metrics.
+ * <li> The period parameter controls how frequently atoms are pushed to logd.
+ * <li> The 'burst' parameter controls how many atoms are pushed at the same time (per period).
+ * </ul>
+ */
+public class LoadtestActivity extends Activity {
+
+ private static final String TAG = "StatsdLoadtest";
+ public static final String TYPE = "type";
+ private static final String PUSH_ALARM = "push_alarm";
+ public static final String PERF_ALARM = "perf_alarm";
+ private static final String START = "start";
+ private static final String STOP = "stop";
+
+ public final static class PusherAlarmReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Intent activityIntent = new Intent(context, LoadtestActivity.class);
+ activityIntent.putExtra(TYPE, PUSH_ALARM);
+ context.startActivity(activityIntent);
+ }
+ }
+
+ public final static class StopperAlarmReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Intent activityIntent = new Intent(context, LoadtestActivity.class);
+ activityIntent.putExtra(TYPE, STOP);
+ context.startActivity(activityIntent);
+ }
+ }
+
+ private AlarmManager mAlarmMgr;
+
+ /** Used to periodically log atoms to logd. */
+ private PendingIntent mPushPendingIntent;
+
+ /** Used to end the loadtest. */
+ private PendingIntent mStopPendingIntent;
+
+ private Button mStartStop;
+ private EditText mReplicationText;
+ private EditText mBucketText;
+ private EditText mPeriodText;
+ private EditText mBurstText;
+ private EditText mDurationText;
+ private TextView mReportText;
+ private CheckBox mPlaceboCheckBox;
+
+ /** When the load test started. */
+ private long mStartedTimeMillis;
+
+ /** For measuring perf data. */
+ private PerfData mPerfData;
+
+ /** For communicating with statsd. */
+ private StatsManager mStatsManager;
+
+ private PowerManager mPowerManager;
+ private WakeLock mWakeLock;
+
+ /**
+ * If true, we only measure the effect of the loadtest infrastructure. No atom are pushed and
+ * the configuration is empty.
+ */
+ private boolean mPlacebo;
+
+ /** The burst size. */
+ private int mBurst;
+
+ /** The metrics replication. */
+ private int mReplication;
+
+ /** The period, in seconds, at which batches of atoms are pushed. */
+ private long mPeriodSecs;
+
+ /** The bucket size, in minutes, for aggregate metrics. */
+ private long mBucketMins;
+
+ /** The duration, in minutes, of the loadtest. */
+ private long mDurationMins;
+
+ /** Whether the loadtest has started. */
+ private boolean mStarted = false;
+
+ /** Orchestrates the logging of pushed events into logd. */
+ private SequencePusher mPusher;
+
+ /** Generates statsd configs. */
+ private ConfigFactory mFactory;
+
+ /** For intra-minute periods. */
+ private final Handler mHandler = new Handler();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Log.d(TAG, "Starting loadtest");
+
+ setContentView(R.layout.activity_loadtest);
+ mReportText = (TextView) findViewById(R.id.report_text);
+ initBurst();
+ initReplication();
+ initBucket();
+ initPeriod();
+ initDuration();
+ initPlacebo();
+
+ // Hide the keyboard outside edit texts.
+ findViewById(R.id.outside).setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ InputMethodManager imm =
+ (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (getCurrentFocus() != null) {
+ imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
+ }
+ return true;
+ }
+ });
+
+ mStartStop = findViewById(R.id.start_stop);
+ mStartStop.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (mStarted) {
+ stopLoadtest();
+ } else {
+ startLoadtest();
+ }
+ }
+ });
+
+ findViewById(R.id.display_output).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ fetchAndDisplayData();
+ }
+ });
+
+ mAlarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+ mStatsManager = (StatsManager) getSystemService("stats");
+ mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ mFactory = new ConfigFactory(this);
+ stopLoadtest();
+ mReportText.setText("");
+ }
+
+ @Override
+ public void onNewIntent(Intent intent) {
+ String type = intent.getStringExtra(TYPE);
+ if (type == null) {
+ return;
+ }
+ switch (type) {
+ case PERF_ALARM:
+ onPerfAlarm();
+ break;
+ case PUSH_ALARM:
+ onAlarm();
+ break;
+ case START:
+ startLoadtest();
+ break;
+ case STOP:
+ stopLoadtest();
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown type: " + type);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ Log.d(TAG, "Destroying");
+ mPerfData.onDestroy();
+ stopLoadtest();
+ clearConfigs();
+ super.onDestroy();
+ }
+
+ private void onPerfAlarm() {
+ if (mPerfData != null) {
+ mPerfData.onAlarm(this);
+ }
+ // Piggy-back on that alarm to show the elapsed time.
+ long elapsedTimeMins = (long) Math.floor(
+ (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
+ mReportText.setText("Loadtest in progress. Elapsed time = " + elapsedTimeMins + " min(s)");
+ }
+
+ private void onAlarm() {
+ Log.d(TAG, "ON ALARM");
+
+ // Set the next task.
+ scheduleNext();
+
+ // Do the work.
+ mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "StatsdLoadTest");
+ mWakeLock.acquire();
+ if (mPusher != null) {
+ mPusher.next();
+ }
+ mWakeLock.release();
+ mWakeLock = null;
+ }
+
+ /** Schedules the next cycle of pushing atoms into logd. */
+ private void scheduleNext() {
+ Intent intent = new Intent(this, PusherAlarmReceiver.class);
+ intent.putExtra(TYPE, PUSH_ALARM);
+ mPushPendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
+ long nextTime = SystemClock.elapsedRealtime() + mPeriodSecs * 1000;
+ mAlarmMgr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, mPushPendingIntent);
+ }
+
+ private synchronized void startLoadtest() {
+ if (mStarted) {
+ return;
+ }
+
+ // Clean up the state.
+ stopLoadtest();
+
+ // Prepare to push a sequence of atoms to logd.
+ mPusher = new SequencePusher(mBurst, mPlacebo);
+
+ // Create a config and push it to statsd.
+ if (!setConfig(mFactory.getConfig(mReplication, mBucketMins * 60 * 1000, mPlacebo))) {
+ return;
+ }
+
+ // Remember to stop in the future.
+ Intent intent = new Intent(this, StopperAlarmReceiver.class);
+ intent.putExtra(TYPE, STOP);
+ mStopPendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
+ long nextTime = SystemClock.elapsedRealtime() + mDurationMins * 60 * 1000;
+ mAlarmMgr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, mStopPendingIntent);
+
+ // Log atoms.
+ scheduleNext();
+
+ // Start tracking performance.
+ mPerfData = new PerfData(this, mPlacebo, mReplication, mBucketMins, mPeriodSecs, mBurst);
+ mPerfData.startRecording(this);
+
+ mReportText.setText("Loadtest in progress.");
+ mStartedTimeMillis = SystemClock.elapsedRealtime();
+
+ updateStarted(true);
+ }
+
+ private synchronized void stopLoadtest() {
+ if (mPushPendingIntent != null) {
+ Log.d(TAG, "Canceling pre-existing push alarm");
+ mAlarmMgr.cancel(mPushPendingIntent);
+ mPushPendingIntent = null;
+ }
+ if (mStopPendingIntent != null) {
+ Log.d(TAG, "Canceling pre-existing stop alarm");
+ mAlarmMgr.cancel(mStopPendingIntent);
+ mStopPendingIntent = null;
+ }
+ if (mWakeLock != null) {
+ mWakeLock.release();
+ mWakeLock = null;
+ }
+ if (mPerfData != null) {
+ mPerfData.stopRecording(this);
+ mPerfData.onDestroy();
+ mPerfData = null;
+ }
+
+ long elapsedTimeMins = (long) Math.floor(
+ (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
+ mReportText.setText("Loadtest ended. Elapsed time = " + elapsedTimeMins + " min(s)");
+ clearConfigs();
+ updateStarted(false);
+ }
+
+ private synchronized void updateStarted(boolean started) {
+ mStarted = started;
+ mStartStop.setBackgroundColor(started ?
+ Color.parseColor("#FFFF0000") : Color.parseColor("#FF00FF00"));
+ mStartStop.setText(started ? getString(R.string.stop) : getString(R.string.start));
+ updateControlsEnabled();
+ }
+
+ private void updateControlsEnabled() {
+ mBurstText.setEnabled(!mPlacebo && !mStarted);
+ mReplicationText.setEnabled(!mPlacebo && !mStarted);
+ mPeriodText.setEnabled(!mStarted);
+ mBucketText.setEnabled(!mPlacebo && !mStarted);
+ mDurationText.setEnabled(!mStarted);
+ mPlaceboCheckBox.setEnabled(!mStarted);
+ }
+
+ private void fetchAndDisplayData() {
+ if (!statsdRunning()) {
+ return;
+ }
+ if (mStatsManager != null) {
+ byte[] data = mStatsManager.getData(ConfigFactory.CONFIG_NAME);
+ if (data != null) {
+ displayData(data);
+ } else {
+ mReportText.setText("Failed to pull data");
+ }
+ }
+ }
+
+ private void displayData(byte[] data) {
+ com.android.os.StatsLog.ConfigMetricsReportList reports = null;
+ boolean good = false;
+ if (data != null) {
+ try {
+ reports = com.android.os.StatsLog.ConfigMetricsReportList.parseFrom(data);
+ good = true;
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ // display it in the text view.
+ }
+ }
+ int size = data == null ? 0 : data.length;
+ StringBuilder sb = new StringBuilder();
+ sb.append(good ? "Proto parsing OK!" : "Proto parsing Error!");
+ sb.append(" size:").append(size).append("\n");
+
+ if (good && reports != null) {
+ DisplayProtoUtils.displayLogReport(sb, reports);
+ mReportText.setText(sb.toString());
+ }
+ }
+
+ private boolean statsdRunning() {
+ if (IStatsManager.Stub.asInterface(ServiceManager.getService("stats")) == null) {
+ Log.d(TAG, "Statsd not running");
+ Toast.makeText(LoadtestActivity.this, "Statsd NOT running!", Toast.LENGTH_LONG).show();
+ return false;
+ }
+ return true;
+ }
+
+ private int sanitizeInt(int val, int min, int max) {
+ if (val > max) {
+ val = max;
+ } else if (val < min) {
+ val = min;
+ }
+ return val;
+ }
+
+ private void clearConfigs() {
+ // TODO: Clear all configs instead of specific ones.
+ if (mStatsManager != null) {
+ if (!mStatsManager.removeConfiguration("fake")) {
+ Log.d(TAG, "Removed \"fake\" statsd configs.");
+ } else {
+ Log.d(TAG, "Failed to remove \"fake\" config. Loadtest results cannot be trusted.");
+ }
+ if (mStarted) {
+ if (!mStatsManager.removeConfiguration(ConfigFactory.CONFIG_NAME)) {
+ Log.d(TAG, "Removed loadtest statsd configs.");
+ } else {
+ Log.d(TAG, "Failed to remove loadtest configs.");
+ }
+ }
+ }
+ }
+
+ private boolean setConfig(byte[] config) {
+ if (mStatsManager != null) {
+ if (mStatsManager.addConfiguration(ConfigFactory.CONFIG_NAME,
+ config, getPackageName(), LoadtestActivity.this.getClass().getName())) {
+ Log.d(TAG, "Config pushed to statsd");
+ return true;
+ } else {
+ Log.d(TAG, "Failed to push config to statsd");
+ }
+ }
+ return false;
+ }
+
+ private synchronized void setReplication(int replication) {
+ mReplication = replication;
+ }
+
+ private synchronized void setPeriodSecs(long periodSecs) {
+ mPeriodSecs = periodSecs;
+ }
+
+ private synchronized void setBucketMins(long bucketMins) {
+ mBucketMins = bucketMins;
+ }
+
+ private synchronized void setBurst(int burst) {
+ mBurst = burst;
+ }
+
+ private synchronized void setDurationMins(long durationMins) {
+ mDurationMins = durationMins;
+ }
+
+ private synchronized void setPlacebo(boolean placebo) {
+ mPlacebo = placebo;
+ updateControlsEnabled();
+ }
+
+ private void handleFocus(EditText editText) {
+ editText.setOnFocusChangeListener(new OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (!hasFocus && editText.getText().toString().isEmpty()) {
+ editText.setText("-1", TextView.BufferType.EDITABLE);
+ }
+ }
+ });
+ }
+
+ private void initBurst() {
+ mBurst = getResources().getInteger(R.integer.burst_default);
+ mBurstText = (EditText) findViewById(R.id.burst);
+ mBurstText.addTextChangedListener(new NumericalWatcher(mBurstText, 0, 50) {
+ @Override
+ public void onNewValue(int newValue) {
+ setBurst(newValue);
+ }
+ });
+ handleFocus(mBurstText);
+ }
+
+ private void initReplication() {
+ mReplication = getResources().getInteger(R.integer.replication_default);
+ mReplicationText = (EditText) findViewById(R.id.replication);
+ mReplicationText.addTextChangedListener(new NumericalWatcher(mReplicationText, 1, 100) {
+ @Override
+ public void onNewValue(int newValue) {
+ setReplication(newValue);
+ }
+ });
+ handleFocus(mReplicationText);
+ }
+
+ private void initBucket() {
+ mBucketMins = getResources().getInteger(R.integer.bucket_default);
+ mBucketText = (EditText) findViewById(R.id.bucket);
+ mBucketText.addTextChangedListener(new NumericalWatcher(mBucketText, 1, 24 * 60) {
+ @Override
+ public void onNewValue(int newValue) {
+ setBucketMins(newValue);
+ }
+ });
+ handleFocus(mBucketText);
+ }
+
+ private void initPeriod() {
+ mPeriodSecs = getResources().getInteger(R.integer.period_default);
+ mPeriodText = (EditText) findViewById(R.id.period);
+ mPeriodText.addTextChangedListener(new NumericalWatcher(mPeriodText, 1, 60) {
+ @Override
+ public void onNewValue(int newValue) {
+ setPeriodSecs(newValue);
+ }
+ });
+ handleFocus(mPeriodText);
+ }
+
+ private void initDuration() {
+ mDurationMins = getResources().getInteger(R.integer.duration_default);
+ mDurationText = (EditText) findViewById(R.id.duration);
+ mDurationText.addTextChangedListener(new NumericalWatcher(mDurationText, 1, 24 * 60) {
+ @Override
+ public void onNewValue(int newValue) {
+ setDurationMins(newValue);
+ }
+ });
+ handleFocus(mDurationText);
+ }
+
+ private void initPlacebo() {
+ mPlaceboCheckBox = findViewById(R.id.placebo);
+ mPlacebo = false;
+ mPlaceboCheckBox.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ setPlacebo(((CheckBox) view).isChecked());
+ }
+ });
+ }
+}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemInfoParser.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemInfoParser.java
new file mode 100644
index 0000000..01eebf2
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemInfoParser.java
@@ -0,0 +1,69 @@
+/*
+ * 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.statsd.loadtest;
+
+import android.annotation.Nullable;
+import android.os.SystemClock;
+import android.util.Log;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/** Parses PSS info from dumpsys meminfo */
+public class MemInfoParser implements PerfParser {
+
+ private static final Pattern LINE_PATTERN =
+ Pattern.compile("\\s*(\\d*,*\\d*)K:\\s(\\S*)\\s\\.*");
+ private static final String PSS_BY_PROCESS = "Total PSS by process:";
+ private static final String TAG = "loadtest.MemInfoParser";
+
+ private boolean mPssStarted;
+ private boolean mPssEnded;
+ private final long mStartTimeMillis;
+
+ public MemInfoParser(long startTimeMillis) {
+ mStartTimeMillis = startTimeMillis;
+ }
+
+ @Override
+ @Nullable
+ public String parseLine(String line) {
+ if (mPssEnded) {
+ return null;
+ }
+ if (!mPssStarted) {
+ if (line.contains(PSS_BY_PROCESS)) {
+ mPssStarted = true;
+ }
+ return null;
+ }
+ if (line.isEmpty()) {
+ mPssEnded = true;
+ return null;
+ }
+ Matcher lineMatcher = LINE_PATTERN.matcher(line);
+ if (lineMatcher.find() && lineMatcher.group(1) != null && lineMatcher.group(2) != null) {
+ if (lineMatcher.group(2).equals("statsd")) {
+ long timeDeltaMillis = SystemClock.elapsedRealtime() - mStartTimeMillis;
+ return timeDeltaMillis + "," + convertToPss(lineMatcher.group(1));
+ }
+ }
+ return null;
+ }
+
+ private String convertToPss(String input) {
+ return input.replace(",", "");
+ }
+}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemoryDataRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemoryDataRecorder.java
new file mode 100644
index 0000000..d82a0ea
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemoryDataRecorder.java
@@ -0,0 +1,51 @@
+/*
+ * 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.statsd.loadtest;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.util.Log;
+
+public class MemoryDataRecorder extends PerfDataRecorder {
+ private static final String TAG = "loadtest.MemoryDataDataRecorder";
+ private static final String DUMP_FILENAME = TAG + "_dump.tmp";
+
+ private long mStartTimeMillis;
+ private StringBuilder mSb;
+
+ public MemoryDataRecorder(boolean placebo, int replication, long bucketMins, long periodSecs,
+ int burst) {
+ super(placebo, replication, bucketMins, periodSecs, burst);
+ }
+
+ @Override
+ public void startRecording(Context context) {
+ mStartTimeMillis = SystemClock.elapsedRealtime();
+ mSb = new StringBuilder();
+ }
+
+ @Override
+ public void onAlarm(Context context) {
+ Log.d(TAG, "GOT ALARM IN MEM");
+ runDumpsysStats(context, DUMP_FILENAME, "meminfo");
+ readDumpData(context, DUMP_FILENAME, new MemInfoParser(mStartTimeMillis), mSb);
+ }
+
+ @Override
+ public void stopRecording(Context context) {
+ writeData(context, "meminfo_", "time,pss", mSb);
+ }
+}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java
new file mode 100644
index 0000000..81a84f5
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java
@@ -0,0 +1,73 @@
+/*
+ * 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.statsd.loadtest;
+
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.widget.TextView;
+
+public abstract class NumericalWatcher implements TextWatcher {
+
+ private static final String TAG = "loadtest.NumericalWatcher";
+
+ private final TextView mTextView;
+ private final int mMin;
+ private final int mMax;
+ private int currentValue = -1;
+
+ public NumericalWatcher(TextView textView, int min, int max) {
+ mTextView = textView;
+ mMin = min;
+ mMax = max;
+ }
+
+ public abstract void onNewValue(int newValue);
+
+ @Override
+ final public void afterTextChanged(Editable editable) {
+ String s = mTextView.getText().toString();
+ if (s.isEmpty()) {
+ return;
+ }
+ int unsanitized = Integer.parseInt(s);
+ int newValue = sanitize(unsanitized);
+
+ Log.d(TAG, "YOYO " + currentValue + " " + newValue + " " + unsanitized);
+
+ if (currentValue != newValue || unsanitized != newValue) {
+ currentValue = newValue;
+ editable.clear();
+ editable.append(newValue + "");
+ }
+ onNewValue(newValue);
+ }
+
+ @Override
+ final public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ final public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ private int sanitize(int val) {
+ if (val > mMax) {
+ val = mMax;
+ } else if (val < mMin) {
+ val = mMin;
+ }
+ return val;
+ }
+}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java
new file mode 100644
index 0000000..4665247
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java
@@ -0,0 +1,101 @@
+/*
+ * 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.statsd.loadtest;
+
+import android.annotation.Nullable;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.SystemClock;
+import android.util.Log;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/** Prints some information about the device via Dumpsys in order to evaluate health metrics. */
+public class PerfData extends PerfDataRecorder {
+
+ private static final String TAG = "loadtest.PerfData";
+
+ /** Polling period for performance snapshots like memory. */
+ private static final long POLLING_PERIOD_MILLIS = 1 * 60 * 1000;
+
+ public final static class PerfAlarmReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Intent activityIntent = new Intent(context, LoadtestActivity.class);
+ activityIntent.putExtra(LoadtestActivity.TYPE, LoadtestActivity.PERF_ALARM);
+ context.startActivity(activityIntent);
+ }
+ }
+
+ private AlarmManager mAlarmMgr;
+
+ /** Used to periodically poll some dumpsys data. */
+ private PendingIntent mPendingIntent;
+
+ private final Set<PerfDataRecorder> mRecorders;
+
+ public PerfData(Context context, boolean placebo, int replication, long bucketMins,
+ long periodSecs, int burst) {
+ super(placebo, replication, bucketMins, periodSecs, burst);
+ mRecorders = new HashSet();
+ mRecorders.add(new BatteryDataRecorder(placebo, replication, bucketMins, periodSecs, burst));
+ mRecorders.add(new MemoryDataRecorder(placebo, replication, bucketMins, periodSecs, burst));
+ mAlarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ }
+
+ public void onDestroy() {
+ if (mPendingIntent != null) {
+ mAlarmMgr.cancel(mPendingIntent);
+ mPendingIntent = null;
+ }
+ }
+
+ @Override
+ public void startRecording(Context context) {
+ Intent intent = new Intent(context, PerfAlarmReceiver.class);
+ intent.putExtra(LoadtestActivity.TYPE, LoadtestActivity.PERF_ALARM);
+ mPendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
+ mAlarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, -1 /* now */,
+ POLLING_PERIOD_MILLIS, mPendingIntent);
+
+ for (PerfDataRecorder recorder : mRecorders) {
+ recorder.startRecording(context);
+ }
+ }
+
+ @Override
+ public void onAlarm(Context context) {
+ for (PerfDataRecorder recorder : mRecorders) {
+ recorder.onAlarm(context);
+ }
+ }
+
+ @Override
+ public void stopRecording(Context context) {
+ if (mPendingIntent != null) {
+ mAlarmMgr.cancel(mPendingIntent);
+ mPendingIntent = null;
+ }
+
+ for (PerfDataRecorder recorder : mRecorders) {
+ recorder.stopRecording(context);
+ }
+ }
+}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfDataRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfDataRecorder.java
new file mode 100644
index 0000000..15a8e5c
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfDataRecorder.java
@@ -0,0 +1,149 @@
+/*
+ * 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.statsd.loadtest;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Environment;
+import android.util.Log;
+import android.os.Debug;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public abstract class PerfDataRecorder {
+ private static final String TAG = "loadtest.PerfDataRecorder";
+
+ protected final String mFileSuffix;
+ protected final String mColumnSuffix;
+
+ protected PerfDataRecorder(boolean placebo, int replication, long bucketMins, long periodSecs,
+ int burst) {
+ mFileSuffix = new SimpleDateFormat("YYYY_MM_dd_HH_mm_ss").format(new Date());
+ mColumnSuffix = getColumnSuffix(placebo, replication, bucketMins, periodSecs, burst);
+ }
+
+ /** Starts recording performance data. */
+ public abstract void startRecording(Context context);
+
+ /** Called periodically. For the recorder to sample data, if needed. */
+ public abstract void onAlarm(Context context);
+
+ /** Stops recording performance data, and writes it to disk. */
+ public abstract void stopRecording(Context context);
+
+ /** Runs the dumpsys command. */
+ protected void runDumpsysStats(Context context, String dumpFilename, String cmd,
+ String... args) {
+ boolean success = false;
+ // Call dumpsys Dump statistics to a file.
+ FileOutputStream fo = null;
+ try {
+ fo = context.openFileOutput(dumpFilename, Context.MODE_PRIVATE);
+ if (!Debug.dumpService(cmd, fo.getFD(), args)) {
+ Log.w(TAG, "Dumpsys failed.");
+ }
+ success = true;
+ } catch (IOException | SecurityException | NullPointerException e) {
+ // SecurityException may occur when trying to dump multi-user info.
+ // NPE can occur during dumpService (root cause unknown).
+ throw new RuntimeException(e);
+ } finally {
+ closeQuietly(fo);
+ }
+ }
+
+ /**
+ * Reads a text file and parses each line, one by one. The result of the parsing is stored
+ * in the passed {@link StringBuffer}.
+ */
+ protected void readDumpData(Context context, String dumpFilename, PerfParser parser,
+ StringBuilder sb) {
+ FileInputStream fi = null;
+ BufferedReader br = null;
+ try {
+ fi = context.openFileInput(dumpFilename);
+ br = new BufferedReader(new InputStreamReader(fi));
+ String line = br.readLine();
+ while (line != null) {
+ String recordLine = parser.parseLine(line);
+ if (recordLine != null) {
+ sb.append(recordLine).append('\n');
+ }
+ line = br.readLine();
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ closeQuietly(br);
+ }
+ }
+
+ /** Writes CSV data to a file. */
+ protected void writeData(Context context, String filePrefix, String columnPrefix,
+ StringBuilder sb) {
+ File dataFile = new File(getStorageDir(), filePrefix + mFileSuffix + ".csv");
+
+ FileWriter writer = null;
+ try {
+ writer = new FileWriter(dataFile);
+ writer.append(columnPrefix + mColumnSuffix + "\n");
+ writer.append(sb.toString());
+ writer.flush();
+ Log.d(TAG, "Finished writing data at " + dataFile.getAbsolutePath());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ closeQuietly(writer);
+ }
+ }
+
+ /** Gets the suffix to use in the column name for perf data. */
+ private String getColumnSuffix(boolean placebo, int replication, long bucketMins,
+ long periodSecs, int burst) {
+ if (placebo) {
+ return "_placebo_p=" + periodSecs;
+ }
+ return "_r=" + replication + "_bkt=" + bucketMins + "_p=" + periodSecs + "_bst=" + burst;
+ }
+
+
+ private File getStorageDir() {
+ File file = new File(Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_DOCUMENTS), "loadtest");
+ if (!file.mkdirs()) {
+ Log.e(TAG, "Directory not created");
+ }
+ return file;
+ }
+
+ private void closeQuietly(@Nullable Closeable c) {
+ if (c != null) {
+ try {
+ c.close();
+ } catch (IOException ignore) {
+ }
+ }
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java
similarity index 61%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java
index 4ccdea5..e000918 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -13,12 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.statsd.loadtest;
-package com.android.internal.telephony;
+import android.annotation.Nullable;
-import android.telephony.SubscriptionInfo;
+public interface PerfParser {
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
+ /**
+ * Parses one line of the dumpsys output, and returns a string to write to the data file,
+ * or null if no string should be written.
+ */
+ @Nullable String parseLine(String line);
}
-
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/SequencePusher.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/SequencePusher.java
new file mode 100644
index 0000000..d4b2aa4
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/SequencePusher.java
@@ -0,0 +1,165 @@
+/*
+ * 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.statsd.loadtest;
+
+import android.util.Log;
+import android.util.StatsLog;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Manages the pushing of atoms into logd for loadtesting.
+ * We rely on small number of pushed atoms, and a config with metrics based on those atoms.
+ * The atoms are:
+ * <ul>
+ * <li> BatteryLevelChanged - For EventMetric, CountMetric and GaugeMetric (no dimensions).
+ * <li> BleScanResultReceived - For CountMetric and ValueMetric, sliced by uid.
+ * <li> ChargingStateChanged - For DurationMetric (no dimension).
+ * <li> GpsScanStateChanged - For DurationMetric, sliced by uid.
+ * <li> ScreenStateChanged - For Conditions with no dimensions.
+ * <li> AudioStateChanged - For Conditions with dimensions (uid).
+ * </ul>
+ * The sequence is played over and over at a given frequency.
+ */
+public class SequencePusher {
+ private static final String TAG = "SequencePusher";
+
+ /** Some atoms are pushed in burst of {@code mBurst} events. */
+ private final int mBurst;
+
+ /** If this is true, we don't log anything in logd. */
+ private final boolean mPlacebo;
+
+ /** Current state in the automaton. */
+ private int mCursor = 0;
+
+ public SequencePusher(int burst, boolean placebo) {
+ mBurst = burst;
+ mPlacebo = placebo;
+ }
+
+ /**
+ * Pushes the next atom to logd.
+ * This follows a small automaton which makes the right events and conditions overlap:
+ * (0) Push a burst of BatteryLevelChanged atoms.
+ * (1) Push a burst of BleScanResultReceived atoms.
+ * (2) Push ChargingStateChanged with BATTERY_STATUS_CHARGING once.
+ * (3) Push a burst of GpsScanStateChanged atoms with ON, with a different uid each time.
+ * (4) Push ChargingStateChanged with BATTERY_STATUS_NOT_CHARGING once.
+ * (5) Push a burst GpsScanStateChanged atoms with OFF, with a different uid each time.
+ * (6) Push ScreenStateChanged with STATE_ON once.
+ * (7) Push a burst of AudioStateChanged with ON, with a different uid each time.
+ * (8) Repeat steps (0)-(5).
+ * (9) Push ScreenStateChanged with STATE_OFF once.
+ * (10) Push a burst of AudioStateChanged with OFF, with a different uid each time.
+ * and repeat.
+ */
+ public void next() {
+ Log.d(TAG, "Next step: " + mCursor);
+ if (mPlacebo) {
+ return;
+ }
+ switch (mCursor) {
+ case 0:
+ case 8:
+ for (int i = 0; i < mBurst; i++) {
+ StatsLog.write(StatsLog.BATTERY_LEVEL_CHANGED, 50 + i /* battery_level */);
+ }
+ break;
+ case 1:
+ case 9:
+ for (int i = 0; i < mBurst; i++) {
+ StatsLog.write(StatsLog.BLE_SCAN_RESULT_RECEIVED, i /* uid */,
+ 100 /* num_of_results */);
+ }
+ break;
+ case 2:
+ case 10:
+ StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
+ StatsLog.CHARGING_STATE_CHANGED__CHARGING_STATE__BATTERY_STATUS_CHARGING
+ /* charging_state */);
+ break;
+ case 3:
+ case 11:
+ for (int i = 0; i < mBurst; i++) {
+ StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, i /* uid */,
+ StatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON /* state */);
+ }
+ break;
+ case 4:
+ case 12:
+ StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
+ StatsLog.CHARGING_STATE_CHANGED__CHARGING_STATE__BATTERY_STATUS_NOT_CHARGING
+ /* charging_state */);
+ break;
+ case 5:
+ case 13:
+ for (int i = 0; i < mBurst; i++) {
+ StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, i /* uid */,
+ StatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF /* state */);
+ }
+ break;
+ case 6:
+ StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
+ StatsLog.SCREEN_STATE_CHANGED__DISPLAY_STATE__STATE_ON /* display_state */);
+ break;
+ case 7:
+ for (int i = 0; i < mBurst; i++) {
+ StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
+ StatsLog.AUDIO_STATE_CHANGED__STATE__ON /* state */);
+ }
+ break;
+ case 14:
+ StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
+ StatsLog.SCREEN_STATE_CHANGED__DISPLAY_STATE__STATE_OFF /* display_state */);
+ break;
+ case 15:
+ for (int i = 0; i < mBurst; i++) {
+ StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
+ StatsLog.AUDIO_STATE_CHANGED__STATE__OFF /* state */);
+ }
+ break;
+ default:
+ }
+ mCursor++;
+ if (mCursor > 15) {
+ mCursor = 0;
+ }
+ }
+
+ /**
+ * Properly finishes in order to be close all conditions and durations.
+ */
+ public void finish() {
+ // Screen goes back to off. This will ensure that conditions get back to false.
+ StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
+ StatsLog.SCREEN_STATE_CHANGED__DISPLAY_STATE__STATE_OFF /* display_state */);
+ for (int i = 0; i < mBurst; i++) {
+ StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
+ StatsLog.AUDIO_STATE_CHANGED__STATE__OFF /* state */);
+ }
+ // Stop charging, to ensure the corresponding durations are closed.
+ StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
+ StatsLog.CHARGING_STATE_CHANGED__CHARGING_STATE__BATTERY_STATUS_NOT_CHARGING
+ /* charging_state */);
+ // Stop scanning GPS, to ensure the corresponding conditions get back to false.
+ for (int i = 0; i < mBurst; i++) {
+ StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, i /* uid */,
+ StatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF /* state */);
+ }
+ }
+}
diff --git a/cmds/uiautomator/instrumentation/Android.mk b/cmds/uiautomator/instrumentation/Android.mk
index e6cbdb4..008bb93 100644
--- a/cmds/uiautomator/instrumentation/Android.mk
+++ b/cmds/uiautomator/instrumentation/Android.mk
@@ -22,7 +22,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, testrunner-src) \
$(call all-java-files-under, ../library/core-src)
LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := legacy-android-test junit
+LOCAL_STATIC_JAVA_LIBRARIES := junit
LOCAL_MODULE := uiautomator-instrumentation
# TODO: change this to 18 when it's available
LOCAL_SDK_VERSION := current
diff --git a/cmds/uiautomator/library/Android.mk b/cmds/uiautomator/library/Android.mk
index 4bf856f..22cffe6 100644
--- a/cmds/uiautomator/library/Android.mk
+++ b/cmds/uiautomator/library/Android.mk
@@ -28,8 +28,8 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(uiautomator.core_src_files)
LOCAL_MODULE := uiautomator.core
-LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
+LOCAL_STATIC_JAVA_LIBRARIES := junit
include $(BUILD_STATIC_JAVA_LIBRARY)
###############################################
diff --git a/core/java/Android.bp b/core/java/Android.bp
index d8c7929..b43cf27 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -4,16 +4,16 @@
}
// only used by key_store_service
-cc_library_static {
+cc_library_shared {
name: "libkeystore_aidl",
srcs: ["android/security/IKeystoreService.aidl"],
aidl: {
export_aidl_headers: true,
- include_dirs: ["frameworks/base/core/java/"],
+ include_dirs: [
+ "frameworks/base/core/java/",
+ "system/security/keystore/",
+ ],
},
- header_libs: [
- "libkeystore_headers",
- ],
shared_libs: [
"libbinder",
"libcutils",
@@ -22,7 +22,12 @@
"libhidltransport",
"libhwbinder",
"liblog",
+ "libkeystore_parcelables",
"libselinux",
"libutils",
],
+ export_shared_lib_headers: [
+ "libbinder",
+ "libkeystore_parcelables",
+ ],
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 03a3631..aa099eb 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -7070,7 +7070,13 @@
mActivityTransitionState.enterReady(this);
}
- final void performRestart() {
+ /**
+ * Restart the activity.
+ * @param start Indicates whether the activity should also be started after restart.
+ * The option to not start immediately is needed in case a transaction with
+ * multiple lifecycle transitions is in progress.
+ */
+ final void performRestart(boolean start) {
mCanEnterPictureInPicture = true;
mFragments.noteStateNotSaved();
@@ -7108,12 +7114,14 @@
"Activity " + mComponent.toShortString() +
" did not call through to super.onRestart()");
}
- performStart();
+ if (start) {
+ performStart();
+ }
}
}
final void performResume() {
- performRestart();
+ performRestart(true /* start */);
mFragments.execPendingActions();
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 02b7f8c..9241378 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1944,15 +1944,17 @@
* @param animate Whether we should play an animation for the moving the task
* @param initialBounds If the primary stack gets created, it will use these bounds for the
* docked stack. Pass {@code null} to use default bounds.
+ * @param showRecents If the recents activity should be shown on the other side of the task
+ * going into split-screen mode.
* @hide
*/
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
public void setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop,
- boolean animate, Rect initialBounds) throws SecurityException {
+ boolean animate, Rect initialBounds, boolean showRecents) throws SecurityException {
try {
getService().setTaskWindowingModeSplitScreenPrimary(taskId, createMode, toTop, animate,
- initialBounds);
+ initialBounds, showRecents);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index a46b3c7..d7efa91 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -283,4 +283,20 @@
* @param token The IApplicationToken for the activity
*/
public abstract void setFocusedActivity(IBinder token);
+
+ /**
+ * Set a uid that is allowed to bypass stopped app switches, launching an app
+ * whenever it wants.
+ *
+ * @param type Type of the caller -- unique string the caller supplies to identify itself
+ * and disambiguate with other calles.
+ * @param uid The uid of the app to be allowed, or -1 to clear the uid for this type.
+ * @param userId The user it is allowed for.
+ */
+ public abstract void setAllowAppSwitches(@NonNull String type, int uid, int userId);
+
+ /**
+ * @return true if runtime was restarted, false if it's normal boot
+ */
+ public abstract boolean isRuntimeRestarted();
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 95c5fb5..8a4d29b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -16,6 +16,13 @@
package android.app;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_DESTROY;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_START;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
+import static android.app.servertransaction.ActivityLifecycleItem.PRE_ON_CREATE;
import static android.view.Display.INVALID_DISPLAY;
import android.annotation.NonNull;
@@ -23,6 +30,12 @@
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.backup.BackupAgent;
+import android.app.servertransaction.ActivityLifecycleItem.LifecycleState;
+import android.app.servertransaction.ActivityResultItem;
+import android.app.servertransaction.ClientTransaction;
+import android.app.servertransaction.PendingTransactionActions;
+import android.app.servertransaction.PendingTransactionActions.StopInfo;
+import android.app.servertransaction.TransactionExecutor;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
import android.content.ComponentName;
@@ -82,7 +95,6 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
-import android.os.TransactionTooLargeException;
import android.os.UserHandle;
import android.provider.BlockedNumberContract;
import android.provider.CalendarContract;
@@ -100,12 +112,12 @@
import android.util.EventLog;
import android.util.Log;
import android.util.LogPrinter;
-import android.util.LogWriter;
import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseIntArray;
import android.util.SuperNotCalledException;
+import android.util.proto.ProtoOutputStream;
import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.ThreadedRenderer;
@@ -119,6 +131,7 @@
import android.webkit.WebView;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.ReferrerIntent;
import com.android.internal.os.BinderInternal;
@@ -126,9 +139,9 @@
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.org.conscrypt.OpenSSLSocketImpl;
import com.android.org.conscrypt.TrustedCertificateStore;
+import com.android.server.am.proto.MemInfoProto;
import dalvik.system.BaseDexClassLoader;
import dalvik.system.CloseGuard;
@@ -174,7 +187,7 @@
*
* {@hide}
*/
-public final class ActivityThread {
+public final class ActivityThread extends ClientTransactionHandler {
/** @hide */
public static final String TAG = "ActivityThread";
private static final android.graphics.Bitmap.Config THUMBNAIL_FORMAT = Bitmap.Config.RGB_565;
@@ -186,7 +199,7 @@
private static final boolean DEBUG_BACKUP = false;
public static final boolean DEBUG_CONFIGURATION = false;
private static final boolean DEBUG_SERVICE = false;
- private static final boolean DEBUG_MEMORY_TRIM = false;
+ public static final boolean DEBUG_MEMORY_TRIM = false;
private static final boolean DEBUG_PROVIDER = false;
private static final boolean DEBUG_ORDER = false;
private static final long MIN_TIME_BETWEEN_GCS = 5*1000;
@@ -202,10 +215,6 @@
/** Type for IActivityManager.serviceDoneExecuting: done stopping (destroying) service */
public static final int SERVICE_DONE_EXECUTING_STOP = 2;
- // Details for pausing activity.
- private static final int USER_LEAVING = 1;
- private static final int DONT_REPORT = 2;
-
// Whether to invoke an activity callback after delivering new configuration.
private static final boolean REPORT_TO_ACTIVITY = true;
@@ -285,12 +294,8 @@
final ArrayList<ActivityClientRecord> mRelaunchingActivities = new ArrayList<>();
@GuardedBy("mResourcesManager")
Configuration mPendingConfiguration = null;
- // Because we merge activity relaunch operations we can't depend on the ordering provided by
- // the handler messages. We need to introduce secondary ordering mechanism, which will allow
- // us to drop certain events, if we know that they happened before relaunch we already executed.
- // This represents the order of receiving the request from AM.
- @GuardedBy("mResourcesManager")
- int mLifecycleSeq = 0;
+ // An executor that performs multi-step transactions.
+ private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this);
private final ResourcesManager mResourcesManager;
@@ -338,8 +343,9 @@
Bundle mCoreSettings = null;
- static final class ActivityClientRecord {
- IBinder token;
+ /** Activity client record, used for bookkeeping for the real {@link Activity} instance. */
+ public static final class ActivityClientRecord {
+ public IBinder token;
int ident;
Intent intent;
String referrer;
@@ -351,6 +357,7 @@
Activity parent;
String embeddedID;
Activity.NonConfigurationInstances lastNonConfigurationInstances;
+ // TODO(lifecycler): Use mLifecycleState instead.
boolean paused;
boolean stopped;
boolean hideForNow;
@@ -367,13 +374,13 @@
ActivityInfo activityInfo;
CompatibilityInfo compatInfo;
- LoadedApk packageInfo;
+ public LoadedApk packageInfo;
List<ResultInfo> pendingResults;
List<ReferrerIntent> pendingIntents;
boolean startsNotResumed;
- boolean isForward;
+ public final boolean isForward;
int pendingConfigChanges;
boolean onlyLocalRequest;
@@ -381,15 +388,42 @@
WindowManager mPendingRemoveWindowManager;
boolean mPreserveWindow;
- // Set for relaunch requests, indicates the order number of the relaunch operation, so it
- // can be compared with other lifecycle operations.
- int relaunchSeq = 0;
+ @LifecycleState
+ private int mLifecycleState = PRE_ON_CREATE;
- // Can only be accessed from the UI thread. This represents the latest processed message
- // that is related to lifecycle events/
- int lastProcessedSeq = 0;
+ @VisibleForTesting
+ public ActivityClientRecord() {
+ this.isForward = false;
+ init();
+ }
- ActivityClientRecord() {
+ public ActivityClientRecord(IBinder token, Intent intent, int ident,
+ ActivityInfo info, Configuration overrideConfig, CompatibilityInfo compatInfo,
+ String referrer, IVoiceInteractor voiceInteractor, Bundle state,
+ PersistableBundle persistentState, List<ResultInfo> pendingResults,
+ List<ReferrerIntent> pendingNewIntents, boolean isForward,
+ ProfilerInfo profilerInfo, ClientTransactionHandler client) {
+ this.token = token;
+ this.ident = ident;
+ this.intent = intent;
+ this.referrer = referrer;
+ this.voiceInteractor = voiceInteractor;
+ this.activityInfo = info;
+ this.compatInfo = compatInfo;
+ this.state = state;
+ this.persistentState = persistentState;
+ this.pendingResults = pendingResults;
+ this.pendingIntents = pendingNewIntents;
+ this.isForward = isForward;
+ this.profilerInfo = profilerInfo;
+ this.overrideConfig = overrideConfig;
+ this.packageInfo = client.getPackageInfoNoCheck(activityInfo.applicationInfo,
+ compatInfo);
+ init();
+ }
+
+ /** Common initializer for all constructors. */
+ private void init() {
parent = null;
embeddedID = null;
paused = false;
@@ -401,11 +435,43 @@
throw new IllegalStateException(
"Received config update for non-existing activity");
}
- activity.mMainThread.handleActivityConfigurationChanged(
- new ActivityConfigChangeData(token, overrideConfig), newDisplayId);
+ activity.mMainThread.handleActivityConfigurationChanged(token, overrideConfig,
+ newDisplayId);
};
}
+ /** Get the current lifecycle state. */
+ public int getLifecycleState() {
+ return mLifecycleState;
+ }
+
+ /** Update the current lifecycle state for internal bookkeeping. */
+ public void setState(@LifecycleState int newLifecycleState) {
+ mLifecycleState = newLifecycleState;
+ switch (mLifecycleState) {
+ case ON_CREATE:
+ paused = true;
+ stopped = true;
+ break;
+ case ON_START:
+ paused = true;
+ stopped = false;
+ break;
+ case ON_RESUME:
+ paused = false;
+ stopped = false;
+ break;
+ case ON_PAUSE:
+ paused = true;
+ stopped = false;
+ break;
+ case ON_STOP:
+ paused = true;
+ stopped = true;
+ break;
+ }
+ }
+
public boolean isPreHoneycomb() {
if (activity != null) {
return activity.getApplicationInfo().targetSdkVersion
@@ -469,16 +535,6 @@
}
}
- static final class NewIntentData {
- List<ReferrerIntent> intents;
- IBinder token;
- boolean andPause;
- public String toString() {
- return "NewIntentData{intents=" + intents + " token=" + token
- + " andPause=" + andPause +"}";
- }
- }
-
static final class ReceiverData extends BroadcastReceiver.PendingResult {
public ReceiverData(Intent intent, int resultCode, String resultData, Bundle resultExtras,
boolean ordered, boolean sticky, IBinder token, int sendingUser) {
@@ -644,14 +700,6 @@
String[] args;
}
- static final class ResultData {
- IBinder token;
- List<ResultInfo> results;
- public String toString() {
- return "ResultData{token=" + token + " results" + results + "}";
- }
- }
-
static final class ContextCleanupInfo {
ContextImpl context;
String what;
@@ -679,15 +727,6 @@
int flags;
}
- static final class ActivityConfigChangeData {
- final IBinder activityToken;
- final Configuration overrideConfig;
- public ActivityConfigChangeData(IBinder token, Configuration config) {
- activityToken = token;
- overrideConfig = config;
- }
- }
-
private class ApplicationThread extends IApplicationThread.Stub {
private static final String DB_INFO_FORMAT = " %8s %8s %14s %14s %s";
@@ -702,93 +741,10 @@
}
}
- public final void schedulePauseActivity(IBinder token, boolean finished,
- boolean userLeaving, int configChanges, boolean dontReport) {
- int seq = getLifecycleSeq();
- if (DEBUG_ORDER) Slog.d(TAG, "pauseActivity " + ActivityThread.this
- + " operation received seq: " + seq);
- sendMessage(
- finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
- token,
- (userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0),
- configChanges,
- seq);
- }
-
- public final void scheduleStopActivity(IBinder token, boolean showWindow,
- int configChanges) {
- int seq = getLifecycleSeq();
- if (DEBUG_ORDER) Slog.d(TAG, "stopActivity " + ActivityThread.this
- + " operation received seq: " + seq);
- sendMessage(
- showWindow ? H.STOP_ACTIVITY_SHOW : H.STOP_ACTIVITY_HIDE,
- token, 0, configChanges, seq);
- }
-
- public final void scheduleWindowVisibility(IBinder token, boolean showWindow) {
- sendMessage(
- showWindow ? H.SHOW_WINDOW : H.HIDE_WINDOW,
- token);
- }
-
public final void scheduleSleeping(IBinder token, boolean sleeping) {
sendMessage(H.SLEEPING, token, sleeping ? 1 : 0);
}
- public final void scheduleResumeActivity(IBinder token, int processState,
- boolean isForward, Bundle resumeArgs) {
- int seq = getLifecycleSeq();
- if (DEBUG_ORDER) Slog.d(TAG, "resumeActivity " + ActivityThread.this
- + " operation received seq: " + seq);
- updateProcessState(processState, false);
- sendMessage(H.RESUME_ACTIVITY, token, isForward ? 1 : 0, 0, seq);
- }
-
- public final void scheduleSendResult(IBinder token, List<ResultInfo> results) {
- ResultData res = new ResultData();
- res.token = token;
- res.results = results;
- sendMessage(H.SEND_RESULT, res);
- }
-
- // we use token to identify this activity without having to send the
- // activity itself back to the activity manager. (matters more with ipc)
- @Override
- public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
- ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
- CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
- int procState, Bundle state, PersistableBundle persistentState,
- List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
- boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
-
- updateProcessState(procState, false);
-
- ActivityClientRecord r = new ActivityClientRecord();
-
- r.token = token;
- r.ident = ident;
- r.intent = intent;
- r.referrer = referrer;
- r.voiceInteractor = voiceInteractor;
- r.activityInfo = info;
- r.compatInfo = compatInfo;
- r.state = state;
- r.persistentState = persistentState;
-
- r.pendingResults = pendingResults;
- r.pendingIntents = pendingNewIntents;
-
- r.startsNotResumed = notResumed;
- r.isForward = isForward;
-
- r.profilerInfo = profilerInfo;
-
- r.overrideConfig = overrideConfig;
- updatePendingConfiguration(curConfig);
-
- sendMessage(H.LAUNCH_ACTIVITY, r);
- }
-
@Override
public final void scheduleRelaunchActivity(IBinder token,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
@@ -798,22 +754,6 @@
configChanges, notResumed, config, overrideConfig, true, preserveWindow);
}
- public final void scheduleNewIntent(
- List<ReferrerIntent> intents, IBinder token, boolean andPause) {
- NewIntentData data = new NewIntentData();
- data.intents = intents;
- data.token = token;
- data.andPause = andPause;
-
- sendMessage(H.NEW_INTENT, data);
- }
-
- public final void scheduleDestroyActivity(IBinder token, boolean finishing,
- int configChanges) {
- sendMessage(H.DESTROY_ACTIVITY, token, finishing ? 1 : 0,
- configChanges);
- }
-
public final void scheduleReceiver(Intent intent, ActivityInfo info,
CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
boolean sync, int sendingUser, int processState) {
@@ -949,11 +889,6 @@
sendMessage(H.SUICIDE, null);
}
- public void scheduleConfigurationChanged(Configuration config) {
- updatePendingConfiguration(config);
- sendMessage(H.CONFIGURATION_CHANGED, config);
- }
-
public void scheduleApplicationInfoChanged(ApplicationInfo ai) {
sendMessage(H.APPLICATION_INFO_CHANGED, ai);
}
@@ -1016,20 +951,6 @@
}
@Override
- public void scheduleActivityConfigurationChanged(
- IBinder token, Configuration overrideConfig) {
- sendMessage(H.ACTIVITY_CONFIGURATION_CHANGED,
- new ActivityConfigChangeData(token, overrideConfig));
- }
-
- @Override
- public void scheduleActivityMovedToDisplay(IBinder token, int displayId,
- Configuration overrideConfig) {
- sendMessage(H.ACTIVITY_MOVED_TO_DISPLAY,
- new ActivityConfigChangeData(token, overrideConfig), displayId);
- }
-
- @Override
public void profilerControl(boolean start, ProfilerInfo profilerInfo, int profileType) {
sendMessage(H.PROFILER_CONTROL, profilerInfo, start ? 1 : 0, profileType);
}
@@ -1427,26 +1348,6 @@
}
@Override
- public void scheduleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode,
- Configuration overrideConfig) throws RemoteException {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = token;
- args.arg2 = overrideConfig;
- args.argi1 = isInMultiWindowMode ? 1 : 0;
- sendMessage(H.MULTI_WINDOW_MODE_CHANGED, args);
- }
-
- @Override
- public void schedulePictureInPictureModeChanged(IBinder token, boolean isInPipMode,
- Configuration overrideConfig) throws RemoteException {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = token;
- args.arg2 = overrideConfig;
- args.argi1 = isInPipMode ? 1 : 0;
- sendMessage(H.PICTURE_IN_PICTURE_MODE_CHANGED, args);
- }
-
- @Override
public void scheduleLocalVoiceInteractionStarted(IBinder token,
IVoiceInteractor voiceInteractor) throws RemoteException {
SomeArgs args = SomeArgs.obtain();
@@ -1459,28 +1360,26 @@
public void handleTrustStorageUpdate() {
NetworkSecurityPolicy.getInstance().handleTrustStorageUpdate();
}
- }
- private int getLifecycleSeq() {
- synchronized (mResourcesManager) {
- return mLifecycleSeq++;
+ @Override
+ public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
+ ActivityThread.this.scheduleTransaction(transaction);
}
}
- private class H extends Handler {
- public static final int LAUNCH_ACTIVITY = 100;
- public static final int PAUSE_ACTIVITY = 101;
- public static final int PAUSE_ACTIVITY_FINISHING= 102;
- public static final int STOP_ACTIVITY_SHOW = 103;
- public static final int STOP_ACTIVITY_HIDE = 104;
- public static final int SHOW_WINDOW = 105;
- public static final int HIDE_WINDOW = 106;
- public static final int RESUME_ACTIVITY = 107;
- public static final int SEND_RESULT = 108;
- public static final int DESTROY_ACTIVITY = 109;
+ @Override
+ public void updatePendingConfiguration(Configuration config) {
+ mAppThread.updatePendingConfiguration(config);
+ }
+
+ @Override
+ public void updateProcessState(int processState, boolean fromIpc) {
+ mAppThread.updateProcessState(processState, fromIpc);
+ }
+
+ class H extends Handler {
public static final int BIND_APPLICATION = 110;
public static final int EXIT_APPLICATION = 111;
- public static final int NEW_INTENT = 112;
public static final int RECEIVER = 113;
public static final int CREATE_SERVICE = 114;
public static final int SERVICE_ARGS = 115;
@@ -1493,7 +1392,6 @@
public static final int UNBIND_SERVICE = 122;
public static final int DUMP_SERVICE = 123;
public static final int LOW_MEMORY = 124;
- public static final int ACTIVITY_CONFIGURATION_CHANGED = 125;
public static final int RELAUNCH_ACTIVITY = 126;
public static final int PROFILER_CONTROL = 127;
public static final int CREATE_BACKUP_AGENT = 128;
@@ -1518,30 +1416,17 @@
public static final int ENTER_ANIMATION_COMPLETE = 149;
public static final int START_BINDER_TRACKING = 150;
public static final int STOP_BINDER_TRACKING_AND_DUMP = 151;
- public static final int MULTI_WINDOW_MODE_CHANGED = 152;
- public static final int PICTURE_IN_PICTURE_MODE_CHANGED = 153;
public static final int LOCAL_VOICE_INTERACTION_STARTED = 154;
public static final int ATTACH_AGENT = 155;
public static final int APPLICATION_INFO_CHANGED = 156;
- public static final int ACTIVITY_MOVED_TO_DISPLAY = 157;
public static final int RUN_ISOLATED_ENTRY_POINT = 158;
+ public static final int EXECUTE_TRANSACTION = 159;
String codeToString(int code) {
if (DEBUG_MESSAGES) {
switch (code) {
- case LAUNCH_ACTIVITY: return "LAUNCH_ACTIVITY";
- case PAUSE_ACTIVITY: return "PAUSE_ACTIVITY";
- case PAUSE_ACTIVITY_FINISHING: return "PAUSE_ACTIVITY_FINISHING";
- case STOP_ACTIVITY_SHOW: return "STOP_ACTIVITY_SHOW";
- case STOP_ACTIVITY_HIDE: return "STOP_ACTIVITY_HIDE";
- case SHOW_WINDOW: return "SHOW_WINDOW";
- case HIDE_WINDOW: return "HIDE_WINDOW";
- case RESUME_ACTIVITY: return "RESUME_ACTIVITY";
- case SEND_RESULT: return "SEND_RESULT";
- case DESTROY_ACTIVITY: return "DESTROY_ACTIVITY";
case BIND_APPLICATION: return "BIND_APPLICATION";
case EXIT_APPLICATION: return "EXIT_APPLICATION";
- case NEW_INTENT: return "NEW_INTENT";
case RECEIVER: return "RECEIVER";
case CREATE_SERVICE: return "CREATE_SERVICE";
case SERVICE_ARGS: return "SERVICE_ARGS";
@@ -1553,8 +1438,6 @@
case UNBIND_SERVICE: return "UNBIND_SERVICE";
case DUMP_SERVICE: return "DUMP_SERVICE";
case LOW_MEMORY: return "LOW_MEMORY";
- case ACTIVITY_CONFIGURATION_CHANGED: return "ACTIVITY_CONFIGURATION_CHANGED";
- case ACTIVITY_MOVED_TO_DISPLAY: return "ACTIVITY_MOVED_TO_DISPLAY";
case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY";
case PROFILER_CONTROL: return "PROFILER_CONTROL";
case CREATE_BACKUP_AGENT: return "CREATE_BACKUP_AGENT";
@@ -1577,12 +1460,11 @@
case INSTALL_PROVIDER: return "INSTALL_PROVIDER";
case ON_NEW_ACTIVITY_OPTIONS: return "ON_NEW_ACTIVITY_OPTIONS";
case ENTER_ANIMATION_COMPLETE: return "ENTER_ANIMATION_COMPLETE";
- case MULTI_WINDOW_MODE_CHANGED: return "MULTI_WINDOW_MODE_CHANGED";
- case PICTURE_IN_PICTURE_MODE_CHANGED: return "PICTURE_IN_PICTURE_MODE_CHANGED";
case LOCAL_VOICE_INTERACTION_STARTED: return "LOCAL_VOICE_INTERACTION_STARTED";
case ATTACH_AGENT: return "ATTACH_AGENT";
case APPLICATION_INFO_CHANGED: return "APPLICATION_INFO_CHANGED";
case RUN_ISOLATED_ENTRY_POINT: return "RUN_ISOLATED_ENTRY_POINT";
+ case EXECUTE_TRANSACTION: return "EXECUTE_TRANSACTION";
}
}
return Integer.toString(code);
@@ -1590,76 +1472,12 @@
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
- case LAUNCH_ACTIVITY: {
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
- final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
-
- r.packageInfo = getPackageInfoNoCheck(
- r.activityInfo.applicationInfo, r.compatInfo);
- handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- } break;
case RELAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
handleRelaunchActivity(r);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
- case PAUSE_ACTIVITY: {
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
- SomeArgs args = (SomeArgs) msg.obj;
- handlePauseActivity((IBinder) args.arg1, false,
- (args.argi1 & USER_LEAVING) != 0, args.argi2,
- (args.argi1 & DONT_REPORT) != 0, args.argi3);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- } break;
- case PAUSE_ACTIVITY_FINISHING: {
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
- SomeArgs args = (SomeArgs) msg.obj;
- handlePauseActivity((IBinder) args.arg1, true, (args.argi1 & USER_LEAVING) != 0,
- args.argi2, (args.argi1 & DONT_REPORT) != 0, args.argi3);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- } break;
- case STOP_ACTIVITY_SHOW: {
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
- SomeArgs args = (SomeArgs) msg.obj;
- handleStopActivity((IBinder) args.arg1, true, args.argi2, args.argi3);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- } break;
- case STOP_ACTIVITY_HIDE: {
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
- SomeArgs args = (SomeArgs) msg.obj;
- handleStopActivity((IBinder) args.arg1, false, args.argi2, args.argi3);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- } break;
- case SHOW_WINDOW:
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityShowWindow");
- handleWindowVisibility((IBinder)msg.obj, true);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- break;
- case HIDE_WINDOW:
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityHideWindow");
- handleWindowVisibility((IBinder)msg.obj, false);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- break;
- case RESUME_ACTIVITY:
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
- SomeArgs args = (SomeArgs) msg.obj;
- handleResumeActivity((IBinder) args.arg1, true, args.argi1 != 0, true,
- args.argi3, "RESUME_ACTIVITY");
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- break;
- case SEND_RESULT:
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDeliverResult");
- handleSendResult((ResultData)msg.obj);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- break;
- case DESTROY_ACTIVITY:
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy");
- handleDestroyActivity((IBinder)msg.obj, msg.arg1 != 0,
- msg.arg2, false);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- break;
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
@@ -1672,11 +1490,6 @@
}
Looper.myLooper().quit();
break;
- case NEW_INTENT:
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityNewIntent");
- handleNewIntent((NewIntentData)msg.obj);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- break;
case RECEIVER:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp");
handleReceiver((ReceiverData)msg.obj);
@@ -1708,15 +1521,7 @@
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case CONFIGURATION_CHANGED:
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged");
- mCurDefaultDisplayDpi = ((Configuration)msg.obj).densityDpi;
- mUpdatingSystemConfig = true;
- try {
- handleConfigurationChanged((Configuration) msg.obj, null);
- } finally {
- mUpdatingSystemConfig = false;
- }
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ handleConfigurationChanged((Configuration) msg.obj);
break;
case CLEAN_UP_CONTEXT:
ContextCleanupInfo cci = (ContextCleanupInfo)msg.obj;
@@ -1733,18 +1538,6 @@
handleLowMemory();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
- case ACTIVITY_CONFIGURATION_CHANGED:
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged");
- handleActivityConfigurationChanged((ActivityConfigChangeData) msg.obj,
- INVALID_DISPLAY);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- break;
- case ACTIVITY_MOVED_TO_DISPLAY:
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityMovedToDisplay");
- handleActivityConfigurationChanged((ActivityConfigChangeData) msg.obj,
- msg.arg1 /* displayId */);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- break;
case PROFILER_CONTROL:
handleProfilerControl(msg.arg1 != 0, (ProfilerInfo)msg.obj, msg.arg2);
break;
@@ -1828,16 +1621,6 @@
case STOP_BINDER_TRACKING_AND_DUMP:
handleStopBinderTrackingAndDump((ParcelFileDescriptor) msg.obj);
break;
- case MULTI_WINDOW_MODE_CHANGED:
- handleMultiWindowModeChanged((IBinder) ((SomeArgs) msg.obj).arg1,
- ((SomeArgs) msg.obj).argi1 == 1,
- (Configuration) ((SomeArgs) msg.obj).arg2);
- break;
- case PICTURE_IN_PICTURE_MODE_CHANGED:
- handlePictureInPictureModeChanged((IBinder) ((SomeArgs) msg.obj).arg1,
- ((SomeArgs) msg.obj).argi1 == 1,
- (Configuration) ((SomeArgs) msg.obj).arg2);
- break;
case LOCAL_VOICE_INTERACTION_STARTED:
handleLocalVoiceInteractionStarted((IBinder) ((SomeArgs) msg.obj).arg1,
(IVoiceInteractor) ((SomeArgs) msg.obj).arg2);
@@ -1857,6 +1640,9 @@
handleRunIsolatedEntryPoint((String) ((SomeArgs) msg.obj).arg1,
(String[]) ((SomeArgs) msg.obj).arg2);
break;
+ case EXECUTE_TRANSACTION:
+ mTransactionExecutor.execute(((ClientTransaction) msg.obj));
+ break;
}
Object obj = msg.obj;
if (obj instanceof SomeArgs) {
@@ -2065,6 +1851,7 @@
registerPackage);
}
+ @Override
public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
CompatibilityInfo compatInfo) {
return getPackageInfo(ai, compatInfo, null, false, true, false);
@@ -2530,6 +2317,167 @@
}
}
+ /**
+ * Dump heap info to proto.
+ *
+ * @param hasSwappedOutPss determines whether to use dirtySwap or dirtySwapPss
+ */
+ private static void dumpHeap(ProtoOutputStream proto, long fieldId, String name,
+ int pss, int cleanPss, int sharedDirty, int privateDirty,
+ int sharedClean, int privateClean,
+ boolean hasSwappedOutPss, int dirtySwap, int dirtySwapPss) {
+ final long token = proto.start(fieldId);
+
+ proto.write(MemInfoProto.NativeProcess.MemoryInfo.NAME, name);
+ proto.write(MemInfoProto.NativeProcess.MemoryInfo.TOTAL_PSS_KB, pss);
+ proto.write(MemInfoProto.NativeProcess.MemoryInfo.CLEAN_PSS_KB, cleanPss);
+ proto.write(MemInfoProto.NativeProcess.MemoryInfo.SHARED_DIRTY_KB, sharedDirty);
+ proto.write(MemInfoProto.NativeProcess.MemoryInfo.PRIVATE_DIRTY_KB, privateDirty);
+ proto.write(MemInfoProto.NativeProcess.MemoryInfo.SHARED_CLEAN_KB, sharedClean);
+ proto.write(MemInfoProto.NativeProcess.MemoryInfo.PRIVATE_CLEAN_KB, privateClean);
+ if (hasSwappedOutPss) {
+ proto.write(MemInfoProto.NativeProcess.MemoryInfo.DIRTY_SWAP_PSS_KB, dirtySwapPss);
+ } else {
+ proto.write(MemInfoProto.NativeProcess.MemoryInfo.DIRTY_SWAP_KB, dirtySwap);
+ }
+
+ proto.end(token);
+ }
+
+ /**
+ * Dump mem info data to proto.
+ */
+ public static void dumpMemInfoTable(ProtoOutputStream proto, Debug.MemoryInfo memInfo,
+ boolean dumpDalvik, boolean dumpSummaryOnly,
+ long nativeMax, long nativeAllocated, long nativeFree,
+ long dalvikMax, long dalvikAllocated, long dalvikFree) {
+
+ if (!dumpSummaryOnly) {
+ final long nhToken = proto.start(MemInfoProto.NativeProcess.NATIVE_HEAP);
+ dumpHeap(proto, MemInfoProto.NativeProcess.HeapInfo.MEM_INFO, "Native Heap",
+ memInfo.nativePss, memInfo.nativeSwappablePss, memInfo.nativeSharedDirty,
+ memInfo.nativePrivateDirty, memInfo.nativeSharedClean,
+ memInfo.nativePrivateClean, memInfo.hasSwappedOutPss,
+ memInfo.nativeSwappedOut, memInfo.nativeSwappedOutPss);
+ proto.write(MemInfoProto.NativeProcess.HeapInfo.HEAP_SIZE_KB, nativeMax);
+ proto.write(MemInfoProto.NativeProcess.HeapInfo.HEAP_ALLOC_KB, nativeAllocated);
+ proto.write(MemInfoProto.NativeProcess.HeapInfo.HEAP_FREE_KB, nativeFree);
+ proto.end(nhToken);
+
+ final long dvToken = proto.start(MemInfoProto.NativeProcess.DALVIK_HEAP);
+ dumpHeap(proto, MemInfoProto.NativeProcess.HeapInfo.MEM_INFO, "Dalvik Heap",
+ memInfo.dalvikPss, memInfo.dalvikSwappablePss, memInfo.dalvikSharedDirty,
+ memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean,
+ memInfo.dalvikPrivateClean, memInfo.hasSwappedOutPss,
+ memInfo.dalvikSwappedOut, memInfo.dalvikSwappedOutPss);
+ proto.write(MemInfoProto.NativeProcess.HeapInfo.HEAP_SIZE_KB, dalvikMax);
+ proto.write(MemInfoProto.NativeProcess.HeapInfo.HEAP_ALLOC_KB, dalvikAllocated);
+ proto.write(MemInfoProto.NativeProcess.HeapInfo.HEAP_FREE_KB, dalvikFree);
+ proto.end(dvToken);
+
+ int otherPss = memInfo.otherPss;
+ int otherSwappablePss = memInfo.otherSwappablePss;
+ int otherSharedDirty = memInfo.otherSharedDirty;
+ int otherPrivateDirty = memInfo.otherPrivateDirty;
+ int otherSharedClean = memInfo.otherSharedClean;
+ int otherPrivateClean = memInfo.otherPrivateClean;
+ int otherSwappedOut = memInfo.otherSwappedOut;
+ int otherSwappedOutPss = memInfo.otherSwappedOutPss;
+
+ for (int i = 0; i < Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
+ final int myPss = memInfo.getOtherPss(i);
+ final int mySwappablePss = memInfo.getOtherSwappablePss(i);
+ final int mySharedDirty = memInfo.getOtherSharedDirty(i);
+ final int myPrivateDirty = memInfo.getOtherPrivateDirty(i);
+ final int mySharedClean = memInfo.getOtherSharedClean(i);
+ final int myPrivateClean = memInfo.getOtherPrivateClean(i);
+ final int mySwappedOut = memInfo.getOtherSwappedOut(i);
+ final int mySwappedOutPss = memInfo.getOtherSwappedOutPss(i);
+ if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
+ || mySharedClean != 0 || myPrivateClean != 0
+ || (memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut) != 0) {
+ dumpHeap(proto, MemInfoProto.NativeProcess.OTHER_HEAPS,
+ Debug.MemoryInfo.getOtherLabel(i),
+ myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
+ mySharedClean, myPrivateClean,
+ memInfo.hasSwappedOutPss, mySwappedOut, mySwappedOutPss);
+
+ otherPss -= myPss;
+ otherSwappablePss -= mySwappablePss;
+ otherSharedDirty -= mySharedDirty;
+ otherPrivateDirty -= myPrivateDirty;
+ otherSharedClean -= mySharedClean;
+ otherPrivateClean -= myPrivateClean;
+ otherSwappedOut -= mySwappedOut;
+ otherSwappedOutPss -= mySwappedOutPss;
+ }
+ }
+
+ dumpHeap(proto, MemInfoProto.NativeProcess.UNKNOWN_HEAP, "Unknown",
+ otherPss, otherSwappablePss,
+ otherSharedDirty, otherPrivateDirty, otherSharedClean, otherPrivateClean,
+ memInfo.hasSwappedOutPss, otherSwappedOut, otherSwappedOutPss);
+ final long tToken = proto.start(MemInfoProto.NativeProcess.TOTAL_HEAP);
+ dumpHeap(proto, MemInfoProto.NativeProcess.HeapInfo.MEM_INFO, "TOTAL",
+ memInfo.getTotalPss(), memInfo.getTotalSwappablePss(),
+ memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
+ memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(),
+ memInfo.hasSwappedOutPss, memInfo.getTotalSwappedOut(),
+ memInfo.getTotalSwappedOutPss());
+ proto.write(MemInfoProto.NativeProcess.HeapInfo.HEAP_SIZE_KB, nativeMax + dalvikMax);
+ proto.write(MemInfoProto.NativeProcess.HeapInfo.HEAP_ALLOC_KB,
+ nativeAllocated + dalvikAllocated);
+ proto.write(MemInfoProto.NativeProcess.HeapInfo.HEAP_FREE_KB, nativeFree + dalvikFree);
+ proto.end(tToken);
+
+ if (dumpDalvik) {
+ for (int i = Debug.MemoryInfo.NUM_OTHER_STATS;
+ i < Debug.MemoryInfo.NUM_OTHER_STATS + Debug.MemoryInfo.NUM_DVK_STATS;
+ i++) {
+ final int myPss = memInfo.getOtherPss(i);
+ final int mySwappablePss = memInfo.getOtherSwappablePss(i);
+ final int mySharedDirty = memInfo.getOtherSharedDirty(i);
+ final int myPrivateDirty = memInfo.getOtherPrivateDirty(i);
+ final int mySharedClean = memInfo.getOtherSharedClean(i);
+ final int myPrivateClean = memInfo.getOtherPrivateClean(i);
+ final int mySwappedOut = memInfo.getOtherSwappedOut(i);
+ final int mySwappedOutPss = memInfo.getOtherSwappedOutPss(i);
+ if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
+ || mySharedClean != 0 || myPrivateClean != 0
+ || (memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut) != 0) {
+ dumpHeap(proto, MemInfoProto.NativeProcess.DALVIK_DETAILS,
+ Debug.MemoryInfo.getOtherLabel(i),
+ myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
+ mySharedClean, myPrivateClean,
+ memInfo.hasSwappedOutPss, mySwappedOut, mySwappedOutPss);
+ }
+ }
+ }
+ }
+
+ final long asToken = proto.start(MemInfoProto.NativeProcess.APP_SUMMARY);
+ proto.write(MemInfoProto.NativeProcess.AppSummary.JAVA_HEAP_PSS_KB,
+ memInfo.getSummaryJavaHeap());
+ proto.write(MemInfoProto.NativeProcess.AppSummary.NATIVE_HEAP_PSS_KB,
+ memInfo.getSummaryNativeHeap());
+ proto.write(MemInfoProto.NativeProcess.AppSummary.CODE_PSS_KB, memInfo.getSummaryCode());
+ proto.write(MemInfoProto.NativeProcess.AppSummary.STACK_PSS_KB, memInfo.getSummaryStack());
+ proto.write(MemInfoProto.NativeProcess.AppSummary.GRAPHICS_PSS_KB,
+ memInfo.getSummaryGraphics());
+ proto.write(MemInfoProto.NativeProcess.AppSummary.PRIVATE_OTHER_PSS_KB,
+ memInfo.getSummaryPrivateOther());
+ proto.write(MemInfoProto.NativeProcess.AppSummary.SYSTEM_PSS_KB,
+ memInfo.getSummarySystem());
+ if (memInfo.hasSwappedOutPss) {
+ proto.write(MemInfoProto.NativeProcess.AppSummary.TOTAL_SWAP_PSS,
+ memInfo.getSummaryTotalSwapPss());
+ } else {
+ proto.write(MemInfoProto.NativeProcess.AppSummary.TOTAL_SWAP_PSS,
+ memInfo.getSummaryTotalSwap());
+ }
+ proto.end(asToken);
+ }
+
public void registerOnActivityPausedListener(Activity activity,
OnActivityPausedListener listener) {
synchronized (mOnPauseListeners) {
@@ -2587,13 +2535,21 @@
+ ", comp=" + name
+ ", token=" + token);
}
- return performLaunchActivity(r, null);
+ // TODO(lifecycler): Can't switch to use #handleLaunchActivity() because it will try to
+ // call #reportSizeConfigurations(), but the server might not know anything about the
+ // activity if it was launched from LocalAcvitivyManager.
+ return performLaunchActivity(r);
}
public final Activity getActivity(IBinder token) {
return mActivities.get(token).activity;
}
+ @Override
+ public ActivityClientRecord getActivityClient(IBinder token) {
+ return mActivities.get(token);
+ }
+
public final void sendActivityResult(
IBinder token, String id, int requestCode,
int resultCode, Intent data) {
@@ -2601,10 +2557,16 @@
+ " req=" + requestCode + " res=" + resultCode + " data=" + data);
ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
list.add(new ResultInfo(id, requestCode, resultCode, data));
- mAppThread.scheduleSendResult(token, list);
+ final ClientTransaction clientTransaction = ClientTransaction.obtain(mAppThread, token);
+ clientTransaction.addCallback(ActivityResultItem.obtain(list));
+ try {
+ mAppThread.scheduleTransaction(clientTransaction);
+ } catch (RemoteException e) {
+ // Local scheduling
+ }
}
- private void sendMessage(int what, Object obj) {
+ void sendMessage(int what, Object obj) {
sendMessage(what, obj, 0, 0, false);
}
@@ -2655,9 +2617,8 @@
sendMessage(H.CLEAN_UP_CONTEXT, cci);
}
- private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
- // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
-
+ /** Core implementation of activity launch. */
+ private Activity performLaunchActivity(ActivityClientRecord r) {
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
@@ -2727,9 +2688,6 @@
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
- if (customIntent != null) {
- activity.mIntent = customIntent;
- }
r.lastNonConfigurationInstances = null;
checkAndBlockForNetworkAccess();
activity.mStartedActivity = false;
@@ -2750,37 +2708,8 @@
" did not call through to super.onCreate()");
}
r.activity = activity;
- r.stopped = true;
- if (!r.activity.mFinished) {
- activity.performStart();
- r.stopped = false;
- }
- if (!r.activity.mFinished) {
- if (r.isPersistable()) {
- if (r.state != null || r.persistentState != null) {
- mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
- r.persistentState);
- }
- } else if (r.state != null) {
- mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
- }
- }
- if (!r.activity.mFinished) {
- activity.mCalled = false;
- if (r.isPersistable()) {
- mInstrumentation.callActivityOnPostCreate(activity, r.state,
- r.persistentState);
- } else {
- mInstrumentation.callActivityOnPostCreate(activity, r.state);
- }
- if (!activity.mCalled) {
- throw new SuperNotCalledException(
- "Activity " + r.intent.getComponent().toShortString() +
- " did not call through to super.onPostCreate()");
- }
- }
}
- r.paused = true;
+ r.setState(ON_CREATE);
mActivities.put(r.token, r);
@@ -2798,6 +2727,60 @@
return activity;
}
+ @Override
+ public void handleStartActivity(ActivityClientRecord r,
+ PendingTransactionActions pendingActions) {
+ final Activity activity = r.activity;
+ if (r.activity == null) {
+ // TODO(lifecycler): What do we do in this case?
+ return;
+ }
+ if (!r.stopped) {
+ throw new IllegalStateException("Can't start activity that is not stopped.");
+ }
+ if (r.activity.mFinished) {
+ // TODO(lifecycler): How can this happen?
+ return;
+ }
+
+ // Start
+ activity.performStart();
+ r.setState(ON_START);
+
+ if (pendingActions == null) {
+ // No more work to do.
+ return;
+ }
+
+ // Restore instance state
+ if (pendingActions.shouldRestoreInstanceState()) {
+ if (r.isPersistable()) {
+ if (r.state != null || r.persistentState != null) {
+ mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
+ r.persistentState);
+ }
+ } else if (r.state != null) {
+ mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
+ }
+ }
+
+ // Call postOnCreate()
+ if (pendingActions.shouldCallOnPostCreate()) {
+ activity.mCalled = false;
+ if (r.isPersistable()) {
+ mInstrumentation.callActivityOnPostCreate(activity, r.state,
+ r.persistentState);
+ } else {
+ mInstrumentation.callActivityOnPostCreate(activity, r.state);
+ }
+ if (!activity.mCalled) {
+ throw new SuperNotCalledException(
+ "Activity " + r.intent.getComponent().toShortString()
+ + " did not call through to super.onPostCreate()");
+ }
+ }
+ }
+
/**
* Checks if {@link #mNetworkBlockSeq} is {@link #INVALID_PROC_STATE_SEQ} and if so, returns
* immediately. Otherwise, makes a blocking call to ActivityManagerService to wait for the
@@ -2844,7 +2827,12 @@
return appContext;
}
- private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
+ /**
+ * Extended implementation of activity launch. Used when server requests a launch or relaunch.
+ */
+ @Override
+ public Activity handleLaunchActivity(ActivityClientRecord r,
+ PendingTransactionActions pendingActions) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
@@ -2867,44 +2855,28 @@
}
WindowManagerGlobal.initialize();
- Activity a = performLaunchActivity(r, customIntent);
+ final Activity a = performLaunchActivity(r);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
reportSizeConfigurations(r);
- Bundle oldState = r.state;
- handleResumeActivity(r.token, false, r.isForward,
- !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
-
- if (!r.activity.mFinished && r.startsNotResumed) {
- // The activity manager actually wants this one to start out paused, because it
- // needs to be visible but isn't in the foreground. We accomplish this by going
- // through the normal startup (because activities expect to go through onResume()
- // the first time they run, before their window is displayed), and then pausing it.
- // However, in this case we do -not- need to do the full pause cycle (of freezing
- // and such) because the activity manager assumes it can just retain the current
- // state it has.
- performPauseActivityIfNeeded(r, reason);
-
- // We need to keep around the original state, in case we need to be created again.
- // But we only do this for pre-Honeycomb apps, which always save their state when
- // pausing, so we can not have them save their state when restarting from a paused
- // state. For HC and later, we want to (and can) let the state be saved as the
- // normal part of stopping the activity.
- if (r.isPreHoneycomb()) {
- r.state = oldState;
- }
+ if (!r.activity.mFinished && pendingActions != null) {
+ pendingActions.setOldState(r.state);
+ pendingActions.setRestoreInstanceState(true);
+ pendingActions.setCallOnPostCreate(true);
}
} else {
// If there was an error, for any reason, tell the activity manager to stop us.
try {
ActivityManager.getService()
- .finishActivity(r.token, Activity.RESULT_CANCELED, null,
- Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
+ .finishActivity(r.token, Activity.RESULT_CANCELED, null,
+ Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
+
+ return a;
}
private void reportSizeConfigurations(ActivityClientRecord r) {
@@ -2974,8 +2946,9 @@
}
}
- private void handleNewIntent(NewIntentData data) {
- performNewIntents(data.token, data.intents, data.andPause);
+ @Override
+ public void handleNewIntent(IBinder token, List<ReferrerIntent> intents, boolean andPause) {
+ performNewIntents(token, intents, andPause);
}
public void handleRequestAssistContextExtras(RequestAssistContextExtras cmd) {
@@ -3096,7 +3069,8 @@
}
}
- private void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode,
+ @Override
+ public void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode,
Configuration overrideConfig) {
final ActivityClientRecord r = mActivities.get(token);
if (r != null) {
@@ -3108,7 +3082,8 @@
}
}
- private void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode,
+ @Override
+ public void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode,
Configuration overrideConfig) {
final ActivityClientRecord r = mActivities.get(token);
if (r != null) {
@@ -3545,8 +3520,7 @@
//Slog.i(TAG, "Running services: " + mServices);
}
- public final ActivityClientRecord performResumeActivity(IBinder token,
- boolean clearHide, String reason) {
+ ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide, String reason) {
ActivityClientRecord r = mActivities.get(token);
if (localLOGV) Slog.v(TAG, "Performing resume of " + r
+ " finished=" + r.activity.mFinished);
@@ -3586,10 +3560,9 @@
EventLog.writeEvent(LOG_AM_ON_RESUME_CALLED, UserHandle.myUserId(),
r.activity.getComponentName().getClassName(), reason);
- r.paused = false;
- r.stopped = false;
r.state = null;
r.persistentState = null;
+ r.setState(ON_RESUME);
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
@@ -3619,20 +3592,16 @@
r.mPendingRemoveWindowManager = null;
}
- final void handleResumeActivity(IBinder token,
- boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
- ActivityClientRecord r = mActivities.get(token);
- if (!checkAndUpdateLifecycleSeq(seq, r, "resumeActivity")) {
- return;
- }
-
+ @Override
+ public void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
+ String reason) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;
// TODO Push resumeArgs into the activity for consideration
- r = performResumeActivity(token, clearHide, reason);
+ final ActivityClientRecord r = performResumeActivity(token, clearHide, reason);
if (r != null) {
final Activity a = r.activity;
@@ -3744,16 +3713,6 @@
Looper.myQueue().addIdleHandler(new Idler());
}
r.onlyLocalRequest = false;
-
- // Tell the activity manager we have resumed.
- if (reallyResume) {
- try {
- ActivityManager.getService().activityResumed(token);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- }
-
} else {
// If an exception was thrown when trying to resume, then
// just end this activity.
@@ -3823,21 +3782,18 @@
return thumbnail;
}
- private void handlePauseActivity(IBinder token, boolean finished,
- boolean userLeaving, int configChanges, boolean dontReport, int seq) {
+ @Override
+ public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
+ int configChanges, boolean dontReport, PendingTransactionActions pendingActions) {
ActivityClientRecord r = mActivities.get(token);
- if (DEBUG_ORDER) Slog.d(TAG, "handlePauseActivity " + r + ", seq: " + seq);
- if (!checkAndUpdateLifecycleSeq(seq, r, "pauseActivity")) {
- return;
- }
if (r != null) {
- //Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);
if (userLeaving) {
performUserLeavingActivity(r);
}
r.activity.mConfigChangeFlags |= configChanges;
- performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");
+ performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity",
+ pendingActions);
// Make sure any pending writes are now committed.
if (r.isPreHoneycomb()) {
@@ -3861,13 +3817,15 @@
}
final Bundle performPauseActivity(IBinder token, boolean finished,
- boolean saveState, String reason) {
+ boolean saveState, String reason, PendingTransactionActions pendingActions) {
ActivityClientRecord r = mActivities.get(token);
- return r != null ? performPauseActivity(r, finished, saveState, reason) : null;
+ return r != null
+ ? performPauseActivity(r, finished, saveState, reason, pendingActions)
+ : null;
}
- final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
- boolean saveState, String reason) {
+ private Bundle performPauseActivity(ActivityClientRecord r, boolean finished, boolean saveState,
+ String reason, PendingTransactionActions pendingActions) {
if (r.paused) {
if (r.activity.mFinished) {
// If we are finishing, we won't call onResume() in certain cases.
@@ -3901,6 +3859,18 @@
listeners.get(i).onPaused(r.activity);
}
+ final Bundle oldState = pendingActions != null ? pendingActions.getOldState() : null;
+ if (oldState != null) {
+ // We need to keep around the original state, in case we need to be created again.
+ // But we only do this for pre-Honeycomb apps, which always save their state when
+ // pausing, so we can not have them save their state when restarting from a paused
+ // state. For HC and later, we want to (and can) let the state be saved as the
+ // normal part of stopping the activity.
+ if (r.isPreHoneycomb()) {
+ r.state = oldState;
+ }
+ }
+
return !r.activity.mFinished && saveState ? r.state : null;
}
@@ -3927,7 +3897,7 @@
+ safeToComponentShortString(r.intent) + ": " + e.toString(), e);
}
}
- r.paused = true;
+ r.setState(ON_PAUSE);
}
final void performStopActivity(IBinder token, boolean saveState, String reason) {
@@ -3935,37 +3905,6 @@
performStopActivityInner(r, null, false, saveState, reason);
}
- private static class StopInfo implements Runnable {
- ActivityClientRecord activity;
- Bundle state;
- PersistableBundle persistentState;
- CharSequence description;
-
- @Override public void run() {
- // Tell activity manager we have been stopped.
- try {
- if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + activity);
- ActivityManager.getService().activityStopped(
- activity.token, state, persistentState, description);
- } catch (RemoteException ex) {
- // Dump statistics about bundle to help developers debug
- final LogWriter writer = new LogWriter(Log.WARN, TAG);
- final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
- pw.println("Bundle stats:");
- Bundle.dumpStats(pw, state);
- pw.println("PersistableBundle stats:");
- Bundle.dumpStats(pw, persistentState);
-
- if (ex instanceof TransactionTooLargeException
- && activity.packageInfo.getTargetSdkVersion() < Build.VERSION_CODES.N) {
- Log.e(TAG, "App sent too much data in instance state, so it was ignored", ex);
- return;
- }
- throw ex.rethrowFromSystemServer();
- }
- }
- }
-
private static final class ProviderRefCount {
public final ContentProviderHolder holder;
public final ProviderClientRecord client;
@@ -3996,8 +3935,8 @@
* For the client, we want to call onStop()/onStart() to indicate when
* the activity's UI visibility changes.
*/
- private void performStopActivityInner(ActivityClientRecord r,
- StopInfo info, boolean keepShown, boolean saveState, String reason) {
+ private void performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean keepShown,
+ boolean saveState, String reason) {
if (localLOGV) Slog.v(TAG, "Performing stop of " + r);
if (r != null) {
if (!keepShown && r.stopped) {
@@ -4022,7 +3961,7 @@
// First create a thumbnail for the activity...
// For now, don't create the thumbnail here; we are
// doing that by doing a screen snapshot.
- info.description = r.activity.onCreateDescription();
+ info.setDescription(r.activity.onCreateDescription());
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
@@ -4052,7 +3991,7 @@
+ ": " + e.toString(), e);
}
}
- r.stopped = true;
+ r.setState(ON_STOP);
EventLog.writeEvent(LOG_AM_ON_STOP_CALLED, UserHandle.myUserId(),
r.activity.getComponentName().getClassName(), reason);
}
@@ -4087,15 +4026,14 @@
}
}
- private void handleStopActivity(IBinder token, boolean show, int configChanges, int seq) {
- ActivityClientRecord r = mActivities.get(token);
- if (!checkAndUpdateLifecycleSeq(seq, r, "stopActivity")) {
- return;
- }
+ @Override
+ public void handleStopActivity(IBinder token, boolean show, int configChanges,
+ PendingTransactionActions pendingActions) {
+ final ActivityClientRecord r = mActivities.get(token);
r.activity.mConfigChangeFlags |= configChanges;
- StopInfo info = new StopInfo();
- performStopActivityInner(r, info, show, true, "handleStopActivity");
+ final StopInfo stopInfo = new StopInfo();
+ performStopActivityInner(r, stopInfo, show, true, "handleStopActivity");
if (localLOGV) Slog.v(
TAG, "Finishing stop of " + r + ": show=" + show
@@ -4108,41 +4046,37 @@
QueuedWork.waitToFinish();
}
- // Schedule the call to tell the activity manager we have
- // stopped. We don't do this immediately, because we want to
- // have a chance for any other pending work (in particular memory
- // trim requests) to complete before you tell the activity
- // manager to proceed and allow us to go fully into the background.
- info.activity = r;
- info.state = r.state;
- info.persistentState = r.persistentState;
- mH.post(info);
+ stopInfo.setActivity(r);
+ stopInfo.setState(r.state);
+ stopInfo.setPersistentState(r.persistentState);
+ pendingActions.setStopInfo(stopInfo);
mSomeActivitiesChanged = true;
}
- private static boolean checkAndUpdateLifecycleSeq(int seq, ActivityClientRecord r,
- String action) {
- if (r == null) {
- return true;
- }
- if (seq < r.lastProcessedSeq) {
- if (DEBUG_ORDER) Slog.d(TAG, action + " for " + r + " ignored, because seq=" + seq
- + " < mCurrentLifecycleSeq=" + r.lastProcessedSeq);
- return false;
- }
- r.lastProcessedSeq = seq;
- return true;
+ /**
+ * Schedule the call to tell the activity manager we have stopped. We don't do this
+ * immediately, because we want to have a chance for any other pending work (in particular
+ * memory trim requests) to complete before you tell the activity manager to proceed and allow
+ * us to go fully into the background.
+ */
+ @Override
+ public void reportStop(PendingTransactionActions pendingActions) {
+ mH.post(pendingActions.getStopInfo());
}
- final void performRestartActivity(IBinder token) {
+ @Override
+ public void performRestartActivity(IBinder token, boolean start) {
ActivityClientRecord r = mActivities.get(token);
if (r.stopped) {
- r.activity.performRestart();
- r.stopped = false;
+ r.activity.performRestart(start);
+ if (start) {
+ r.setState(ON_START);
+ }
}
}
- private void handleWindowVisibility(IBinder token, boolean show) {
+ @Override
+ public void handleWindowVisibility(IBinder token, boolean show) {
ActivityClientRecord r = mActivities.get(token);
if (r == null) {
@@ -4157,8 +4091,8 @@
// we are back active so skip it.
unscheduleGcIdler();
- r.activity.performRestart();
- r.stopped = false;
+ r.activity.performRestart(true /* start */);
+ r.setState(ON_START);
}
if (r.activity.mDecor != null) {
if (false) Slog.v(
@@ -4196,7 +4130,7 @@
+ ": " + e.toString(), e);
}
}
- r.stopped = true;
+ r.setState(ON_STOP);
EventLog.writeEvent(LOG_AM_ON_STOP_CALLED, UserHandle.myUserId(),
r.activity.getComponentName().getClassName(), "sleeping");
}
@@ -4214,8 +4148,8 @@
}
} else {
if (r.stopped && r.activity.mVisibleFromServer) {
- r.activity.performRestart();
- r.stopped = false;
+ r.activity.performRestart(true /* start */);
+ r.setState(ON_START);
}
}
}
@@ -4288,8 +4222,9 @@
}
}
- private void handleSendResult(ResultData res) {
- ActivityClientRecord r = mActivities.get(res.token);
+ @Override
+ public void handleSendResult(IBinder token, List<ResultInfo> results) {
+ ActivityClientRecord r = mActivities.get(token);
if (DEBUG_RESULTS) Slog.v(TAG, "Handling send result to " + r);
if (r != null) {
final boolean resumed = !r.paused;
@@ -4323,7 +4258,7 @@
}
}
checkAndBlockForNetworkAccess();
- deliverResults(r, res.results);
+ deliverResults(r, results);
if (resumed) {
r.activity.performResume();
r.activity.mTemporaryPause = false;
@@ -4331,11 +4266,8 @@
}
}
- public final ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing) {
- return performDestroyActivity(token, finishing, 0, false);
- }
-
- private ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
+ /** Core implementation of activity destroy call. */
+ ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
int configChanges, boolean getNonConfigInstance) {
ActivityClientRecord r = mActivities.get(token);
Class<? extends Activity> activityClass = null;
@@ -4362,7 +4294,7 @@
+ ": " + e.toString(), e);
}
}
- r.stopped = true;
+ r.setState(ON_STOP);
EventLog.writeEvent(LOG_AM_ON_STOP_CALLED, UserHandle.myUserId(),
r.activity.getComponentName().getClassName(), "destroy");
}
@@ -4399,6 +4331,7 @@
+ ": " + e.toString(), e);
}
}
+ r.setState(ON_DESTROY);
}
mActivities.remove(token);
StrictMode.decrementExpectedActivityCount(activityClass);
@@ -4410,8 +4343,9 @@
return component == null ? "[Unknown]" : component.toShortString();
}
- private void handleDestroyActivity(IBinder token, boolean finishing,
- int configChanges, boolean getNonConfigInstance) {
+ @Override
+ public void handleDestroyActivity(IBinder token, boolean finishing, int configChanges,
+ boolean getNonConfigInstance) {
ActivityClientRecord r = performDestroyActivity(token, finishing,
configChanges, getNonConfigInstance);
if (r != null) {
@@ -4558,10 +4492,7 @@
target.overrideConfig = overrideConfig;
}
target.pendingConfigChanges |= configChanges;
- target.relaunchSeq = getLifecycleSeq();
}
- if (DEBUG_ORDER) Slog.d(TAG, "relaunchActivity " + ActivityThread.this + ", target "
- + target + " operation received seq: " + target.relaunchSeq);
}
private void handleRelaunchActivity(ActivityClientRecord tmp) {
@@ -4606,12 +4537,6 @@
}
}
- if (tmp.lastProcessedSeq > tmp.relaunchSeq) {
- Slog.wtf(TAG, "For some reason target: " + tmp + " has lower sequence: "
- + tmp.relaunchSeq + " than current sequence: " + tmp.lastProcessedSeq);
- } else {
- tmp.lastProcessedSeq = tmp.relaunchSeq;
- }
if (tmp.createdConfig != null) {
// If the activity manager is passing us its current config,
// assume that is really what we want regardless of what we
@@ -4652,9 +4577,6 @@
r.activity.mConfigChangeFlags |= configChanges;
r.onlyLocalRequest = tmp.onlyLocalRequest;
r.mPreserveWindow = tmp.mPreserveWindow;
- r.lastProcessedSeq = tmp.lastProcessedSeq;
- r.relaunchSeq = tmp.relaunchSeq;
- Intent currentIntent = r.activity.mIntent;
r.activity.mChangingConfigurations = true;
@@ -4680,7 +4602,8 @@
// Need to ensure state is saved.
if (!r.paused) {
- performPauseActivity(r.token, false, r.isPreHoneycomb(), "handleRelaunchActivity");
+ performPauseActivity(r.token, false, r.isPreHoneycomb(), "handleRelaunchActivity",
+ null /* pendingActions */);
}
if (r.state == null && !r.stopped && !r.isPreHoneycomb()) {
callCallActivityOnSaveInstanceState(r);
@@ -4710,7 +4633,15 @@
r.startsNotResumed = tmp.startsNotResumed;
r.overrideConfig = tmp.overrideConfig;
- handleLaunchActivity(r, currentIntent, "handleRelaunchActivity");
+ // TODO(lifecycler): Move relaunch to lifecycler.
+ PendingTransactionActions pendingActions = new PendingTransactionActions();
+ handleLaunchActivity(r, pendingActions);
+ handleStartActivity(r, pendingActions);
+ handleResumeActivity(r.token, false /* clearHide */, r.isForward, "relaunch");
+ if (r.startsNotResumed) {
+ performPauseActivity(r, false /* finished */, r.isPreHoneycomb(), "relaunch",
+ pendingActions);
+ }
if (!tmp.onlyLocalRequest) {
try {
@@ -4982,7 +4913,20 @@
return config;
}
- final void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) {
+ @Override
+ public void handleConfigurationChanged(Configuration config) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged");
+ mCurDefaultDisplayDpi = config.densityDpi;
+ mUpdatingSystemConfig = true;
+ try {
+ handleConfigurationChanged(config, null /* compat */);
+ } finally {
+ mUpdatingSystemConfig = false;
+ }
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
+
+ private void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) {
int configDiff = 0;
@@ -5113,12 +5057,15 @@
/**
* Handle new activity configuration and/or move to a different display.
- * @param data Configuration update data.
+ * @param activityToken Target activity token.
+ * @param overrideConfig Activity override config.
* @param displayId Id of the display where activity was moved to, -1 if there was no move and
* value didn't change.
*/
- void handleActivityConfigurationChanged(ActivityConfigChangeData data, int displayId) {
- ActivityClientRecord r = mActivities.get(data.activityToken);
+ @Override
+ public void handleActivityConfigurationChanged(IBinder activityToken,
+ Configuration overrideConfig, int displayId) {
+ ActivityClientRecord r = mActivities.get(activityToken);
// Check input params.
if (r == null || r.activity == null) {
if (DEBUG_CONFIGURATION) Slog.w(TAG, "Not found target activity to report to: " + r);
@@ -5128,14 +5075,14 @@
&& displayId != r.activity.getDisplay().getDisplayId();
// Perform updates.
- r.overrideConfig = data.overrideConfig;
+ r.overrideConfig = overrideConfig;
final ViewRootImpl viewRoot = r.activity.mDecor != null
? r.activity.mDecor.getViewRootImpl() : null;
if (movedToDifferentDisplay) {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity moved to display, activity:"
+ r.activityInfo.name + ", displayId=" + displayId
- + ", config=" + data.overrideConfig);
+ + ", config=" + overrideConfig);
final Configuration reportedConfig = performConfigurationChangedForActivity(r,
mCompatConfiguration, displayId, true /* movedToDifferentDisplay */);
@@ -5144,7 +5091,7 @@
}
} else {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: "
- + r.activityInfo.name + ", config=" + data.overrideConfig);
+ + r.activityInfo.name + ", config=" + overrideConfig);
performConfigurationChangedForActivity(r, mCompatConfiguration);
}
// Notify the ViewRootImpl instance about configuration changes. It may have initiated this
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 7a4c00f..1dbdb59 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -55,6 +55,7 @@
import android.content.pm.SharedLibraryInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VersionedPackage;
+import android.content.pm.dex.ArtManager;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.Bitmap;
@@ -121,6 +122,8 @@
private UserManager mUserManager;
@GuardedBy("mLock")
private PackageInstaller mInstaller;
+ @GuardedBy("mLock")
+ private ArtManager mArtManager;
@GuardedBy("mDelegates")
private final ArrayList<MoveCallbackDelegate> mDelegates = new ArrayList<>();
@@ -2462,7 +2465,8 @@
if (itemInfo.showUserIcon != UserHandle.USER_NULL) {
Bitmap bitmap = getUserManager().getUserIcon(itemInfo.showUserIcon);
if (bitmap == null) {
- return UserIcons.getDefaultUserIcon(itemInfo.showUserIcon, /* light= */ false);
+ return UserIcons.getDefaultUserIcon(
+ mContext.getResources(), itemInfo.showUserIcon, /* light= */ false);
}
return new BitmapDrawable(bitmap);
}
@@ -2749,4 +2753,18 @@
throw e.rethrowAsRuntimeException();
}
}
+
+ @Override
+ public ArtManager getArtManager() {
+ synchronized (mLock) {
+ if (mArtManager == null) {
+ try {
+ mArtManager = new ArtManager(mPM.getArtManager());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return mArtManager;
+ }
+ }
}
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
new file mode 100644
index 0000000..ef66af0
--- /dev/null
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 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 android.app;
+
+import android.app.servertransaction.ClientTransaction;
+import android.app.servertransaction.PendingTransactionActions;
+import android.content.pm.ApplicationInfo;
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
+import android.os.IBinder;
+
+import com.android.internal.content.ReferrerIntent;
+
+import java.util.List;
+
+/**
+ * Defines operations that a {@link android.app.servertransaction.ClientTransaction} or its items
+ * can perform on client.
+ * @hide
+ */
+public abstract class ClientTransactionHandler {
+
+ // Schedule phase related logic and handlers.
+
+ /** Prepare and schedule transaction for execution. */
+ void scheduleTransaction(ClientTransaction transaction) {
+ transaction.preExecute(this);
+ sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
+ }
+
+ abstract void sendMessage(int what, Object obj);
+
+
+ // Prepare phase related logic and handlers. Methods that inform about about pending changes or
+ // do other internal bookkeeping.
+
+ /** Set pending config in case it will be updated by other transaction item. */
+ public abstract void updatePendingConfiguration(Configuration config);
+
+ /** Set current process state. */
+ public abstract void updateProcessState(int processState, boolean fromIpc);
+
+
+ // Execute phase related logic and handlers. Methods here execute actual lifecycle transactions
+ // and deliver callbacks.
+
+ /** Destroy the activity. */
+ public abstract void handleDestroyActivity(IBinder token, boolean finishing, int configChanges,
+ boolean getNonConfigInstance);
+
+ /** Pause the activity. */
+ public abstract void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
+ int configChanges, boolean dontReport, PendingTransactionActions pendingActions);
+
+ /** Resume the activity. */
+ public abstract void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
+ String reason);
+
+ /** Stop the activity. */
+ public abstract void handleStopActivity(IBinder token, boolean show, int configChanges,
+ PendingTransactionActions pendingActions);
+
+ /** Report that activity was stopped to server. */
+ public abstract void reportStop(PendingTransactionActions pendingActions);
+
+ /** Restart the activity after it was stopped. */
+ public abstract void performRestartActivity(IBinder token, boolean start);
+
+ /** Deliver activity (override) configuration change. */
+ public abstract void handleActivityConfigurationChanged(IBinder activityToken,
+ Configuration overrideConfig, int displayId);
+
+ /** Deliver result from another activity. */
+ public abstract void handleSendResult(IBinder token, List<ResultInfo> results);
+
+ /** Deliver multi-window mode change notification. */
+ public abstract void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode,
+ Configuration overrideConfig);
+
+ /** Deliver new intent. */
+ public abstract void handleNewIntent(IBinder token, List<ReferrerIntent> intents,
+ boolean andPause);
+
+ /** Deliver picture-in-picture mode change notification. */
+ public abstract void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode,
+ Configuration overrideConfig);
+
+ /** Update window visibility. */
+ public abstract void handleWindowVisibility(IBinder token, boolean show);
+
+ /** Perform activity launch. */
+ public abstract Activity handleLaunchActivity(ActivityThread.ActivityClientRecord r,
+ PendingTransactionActions pendingActions);
+
+ /** Perform activity start. */
+ public abstract void handleStartActivity(ActivityThread.ActivityClientRecord r,
+ PendingTransactionActions pendingActions);
+
+ /** Get package info. */
+ public abstract LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
+ CompatibilityInfo compatInfo);
+
+ /** Deliver app configuration change notification. */
+ public abstract void handleConfigurationChanged(Configuration config);
+
+ /**
+ * Get {@link android.app.ActivityThread.ActivityClientRecord} instance that corresponds to the
+ * provided token.
+ */
+ public abstract ActivityThread.ActivityClientRecord getActivityClient(IBinder token);
+}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 5f34322..b0d020a 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -59,11 +59,10 @@
import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
-import android.os.storage.IStorageManager;
+import android.os.storage.StorageManager;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -2457,7 +2456,8 @@
* unable to create, they are filtered by replacing with {@code null}.
*/
private File[] ensureExternalDirsExistOrFilter(File[] dirs) {
- File[] result = new File[dirs.length];
+ final StorageManager sm = getSystemService(StorageManager.class);
+ final File[] result = new File[dirs.length];
for (int i = 0; i < dirs.length; i++) {
File dir = dirs[i];
if (!dir.exists()) {
@@ -2466,15 +2466,8 @@
if (!dir.exists()) {
// Failing to mkdir() may be okay, since we might not have
// enough permissions; ask vold to create on our behalf.
- final IStorageManager storageManager = IStorageManager.Stub.asInterface(
- ServiceManager.getService("mount"));
try {
- final int res = storageManager.mkdirs(
- getPackageName(), dir.getAbsolutePath());
- if (res != 0) {
- Log.w(TAG, "Failed to ensure " + dir + ": " + res);
- dir = null;
- }
+ sm.mkdirs(dir);
} catch (Exception e) {
Log.w(TAG, "Failed to ensure " + dir + ": " + e);
dir = null;
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 2d6308c..84c07ec 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -502,7 +502,7 @@
void reportSizeConfigurations(in IBinder token, in int[] horizontalSizeConfiguration,
in int[] verticalSizeConfigurations, in int[] smallestWidthConfigurations);
boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop,
- boolean animate, in Rect initialBounds);
+ boolean animate, in Rect initialBounds, boolean showRecents);
/**
* Dismisses split-screen multi-window mode.
* {@param toTop} If true the current primary split-screen stack will be placed or left on top.
@@ -667,4 +667,10 @@
void setShowWhenLocked(in IBinder token, boolean showWhenLocked);
void setTurnScreenOn(in IBinder token, boolean turnScreenOn);
+
+ /**
+ * Similar to {@link #startUserInBackground(int userId), but with a listener to report
+ * user unlock progress.
+ */
+ boolean startUserInBackgroundWithListener(int userid, IProgressListener unlockProgressListener);
}
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 487a94a..b25d778 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -20,6 +20,7 @@
import android.app.IUiAutomationConnection;
import android.app.ProfilerInfo;
import android.app.ResultInfo;
+import android.app.servertransaction.ClientTransaction;
import android.content.ComponentName;
import android.content.IIntentReceiver;
import android.content.Intent;
@@ -52,24 +53,6 @@
* {@hide}
*/
oneway interface IApplicationThread {
- void schedulePauseActivity(IBinder token, boolean finished, boolean userLeaving,
- int configChanges, boolean dontReport);
- void scheduleStopActivity(IBinder token, boolean showWindow,
- int configChanges);
- void scheduleWindowVisibility(IBinder token, boolean showWindow);
- void scheduleResumeActivity(IBinder token, int procState, boolean isForward,
- in Bundle resumeArgs);
- void scheduleSendResult(IBinder token, in List<ResultInfo> results);
- void scheduleLaunchActivity(in Intent intent, IBinder token, int ident,
- in ActivityInfo info, in Configuration curConfig, in Configuration overrideConfig,
- in CompatibilityInfo compatInfo, in String referrer, IVoiceInteractor voiceInteractor,
- int procState, in Bundle state, in PersistableBundle persistentState,
- in List<ResultInfo> pendingResults, in List<ReferrerIntent> pendingNewIntents,
- boolean notResumed, boolean isForward, in ProfilerInfo profilerInfo);
- void scheduleNewIntent(
- in List<ReferrerIntent> intent, IBinder token, boolean andPause);
- void scheduleDestroyActivity(IBinder token, boolean finished,
- int configChanges);
void scheduleReceiver(in Intent intent, in ActivityInfo info,
in CompatibilityInfo compatInfo,
int resultCode, in String data, in Bundle extras, boolean sync,
@@ -87,7 +70,6 @@
in Bundle coreSettings, in String buildSerial);
void runIsolatedEntryPoint(in String entryPoint, in String[] entryPointArgs);
void scheduleExit();
- void scheduleConfigurationChanged(in Configuration config);
void scheduleServiceArgs(IBinder token, in ParceledListSlice args);
void updateTimeZone();
void processInBackground();
@@ -101,9 +83,6 @@
int resultCode, in String data, in Bundle extras, boolean ordered,
boolean sticky, int sendingUser, int processState);
void scheduleLowMemory();
- void scheduleActivityConfigurationChanged(IBinder token, in Configuration overrideConfig);
- void scheduleActivityMovedToDisplay(IBinder token, int displayId,
- in Configuration overrideConfig);
void scheduleRelaunchActivity(IBinder token, in List<ResultInfo> pendingResults,
in List<ReferrerIntent> pendingNewIntents, int configChanges, boolean notResumed,
in Configuration config, in Configuration overrideConfig, boolean preserveWindow);
@@ -146,14 +125,11 @@
void notifyCleartextNetwork(in byte[] firstPacket);
void startBinderTracking();
void stopBinderTrackingAndDump(in ParcelFileDescriptor fd);
- void scheduleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode,
- in Configuration newConfig);
- void schedulePictureInPictureModeChanged(IBinder token, boolean isInPictureInPictureMode,
- in Configuration newConfig);
void scheduleLocalVoiceInteractionStarted(IBinder token,
IVoiceInteractor voiceInteractor);
void handleTrustStorageUpdate();
void attachAgent(String path);
void scheduleApplicationInfoChanged(in ApplicationInfo ai);
void setNetworkBlockSeq(long procStateSeq);
+ void scheduleTransaction(in ClientTransaction transaction);
}
diff --git a/core/java/android/app/IBackupAgent.aidl b/core/java/android/app/IBackupAgent.aidl
index a07374b..4a85efd 100644
--- a/core/java/android/app/IBackupAgent.aidl
+++ b/core/java/android/app/IBackupAgent.aidl
@@ -79,7 +79,7 @@
* passed here as a convenience to the agent.
*/
void doRestore(in ParcelFileDescriptor data,
- int appVersionCode, in ParcelFileDescriptor newState,
+ long appVersionCode, in ParcelFileDescriptor newState,
int token, IBackupManager callbackBinder);
/**
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl
index b26117d..d01938b 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -18,6 +18,7 @@
import android.accessibilityservice.IAccessibilityServiceClient;
import android.graphics.Bitmap;
+import android.graphics.Rect;
import android.view.InputEvent;
import android.view.WindowContentFrameStats;
import android.view.WindowAnimationFrameStats;
@@ -37,7 +38,7 @@
void disconnect();
boolean injectInputEvent(in InputEvent event, boolean sync);
boolean setRotation(int rotation);
- Bitmap takeScreenshot(int width, int height);
+ Bitmap takeScreenshot(in Rect crop, int rotation);
boolean clearWindowContentFrameStats(int windowId);
WindowContentFrameStats getWindowContentFrameStats(int windowId);
void clearWindowAnimationFrameStats();
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 1fe2900..d0f84c8 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -382,6 +382,8 @@
}
/**
+ * @deprecated Use {@link #isKeyguardLocked()} instead.
+ *
* If keyguard screen is showing or in restricted key input mode (i.e. in
* keyguard password emergency screen). When in such mode, certain keys,
* such as the Home key and the right soft keys, don't work.
@@ -389,11 +391,7 @@
* @return true if in keyguard restricted input mode.
*/
public boolean inKeyguardRestrictedInputMode() {
- try {
- return mWM.inKeyguardRestrictedInputMode();
- } catch (RemoteException ex) {
- return false;
- }
+ return isKeyguardLocked();
}
/**
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index f6d9710..ebd1014 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -638,8 +638,7 @@
final String defaultSearchPaths = System.getProperty("java.library.path");
final boolean treatVendorApkAsUnbundled = !defaultSearchPaths.contains("/vendor/lib");
if (mApplicationInfo.getCodePath() != null
- && mApplicationInfo.getCodePath().startsWith("/vendor/")
- && treatVendorApkAsUnbundled) {
+ && mApplicationInfo.isVendor() && treatVendorApkAsUnbundled) {
isBundledApp = false;
}
@@ -1647,9 +1646,12 @@
if (dead) {
mConnection.onBindingDied(name);
}
- // If there is a new service, it is now connected.
+ // If there is a new viable service, it is now connected.
if (service != null) {
mConnection.onServiceConnected(name, service);
+ } else {
+ // The binding machinery worked, but the remote returned null from onBind().
+ mConnection.onNullBinding(name);
}
}
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 3b273bc..998ac5f 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -22,6 +22,7 @@
import android.os.Bundle;
import android.util.Log;
import android.view.Window;
+
import com.android.internal.content.ReferrerIntent;
import java.util.ArrayList;
@@ -161,12 +162,12 @@
case CREATED:
if (desiredState == STARTED) {
if (localLOGV) Log.v(TAG, r.id + ": restarting");
- mActivityThread.performRestartActivity(r);
+ mActivityThread.performRestartActivity(r, true /* start */);
r.curState = STARTED;
}
if (desiredState == RESUMED) {
if (localLOGV) Log.v(TAG, r.id + ": restarting and resuming");
- mActivityThread.performRestartActivity(r);
+ mActivityThread.performRestartActivity(r, true /* start */);
mActivityThread.performResumeActivity(r, true, "moveToState-CREATED");
r.curState = RESUMED;
}
@@ -207,7 +208,7 @@
private void performPause(LocalActivityRecord r, boolean finishing) {
final boolean needState = r.instanceState == null;
final Bundle instanceState = mActivityThread.performPauseActivity(
- r, finishing, needState, "performPause");
+ r, finishing, needState, "performPause", null /* pendingActions */);
if (needState) {
r.instanceState = instanceState;
}
@@ -361,7 +362,8 @@
performPause(r, finish);
}
if (localLOGV) Log.v(TAG, r.id + ": destroying");
- mActivityThread.performDestroyActivity(r, finish);
+ mActivityThread.performDestroyActivity(r, finish, 0 /* configChanges */,
+ false /* getNonConfigInstance */);
r.activity = null;
r.window = null;
if (finish) {
@@ -625,7 +627,8 @@
for (int i=0; i<N; i++) {
LocalActivityRecord r = mActivityArray.get(i);
if (localLOGV) Log.v(TAG, r.id + ": destroying");
- mActivityThread.performDestroyActivity(r, finishing);
+ mActivityThread.performDestroyActivity(r, finishing, 0 /* configChanges */,
+ false /* getNonConfigInstance */);
}
mActivities.clear();
mActivityArray.clear();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 42c1347..fb9efe6 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1941,6 +1941,7 @@
mSortKey = parcel.readString();
extras = Bundle.setDefusable(parcel.readBundle(), true); // may be null
+ fixDuplicateExtras();
actions = parcel.createTypedArray(Action.CREATOR); // may be null
@@ -2389,6 +2390,33 @@
};
/**
+ * Parcelling creates multiple copies of objects in {@code extras}. Fix them.
+ * <p>
+ * For backwards compatibility {@code extras} holds some references to "real" member data such
+ * as {@link getLargeIcon()} which is mirrored by {@link #EXTRA_LARGE_ICON}. This is mostly
+ * fine as long as the object stays in one process.
+ * <p>
+ * However, once the notification goes into a parcel each reference gets marshalled separately,
+ * wasting memory. Especially with large images on Auto and TV, this is worth fixing.
+ */
+ private void fixDuplicateExtras() {
+ if (extras != null) {
+ fixDuplicateExtra(mSmallIcon, EXTRA_SMALL_ICON);
+ fixDuplicateExtra(mLargeIcon, EXTRA_LARGE_ICON);
+ }
+ }
+
+ /**
+ * If we find an extra that's exactly the same as one of the "real" fields but refers to a
+ * separate object, replace it with the field's version to avoid holding duplicate copies.
+ */
+ private void fixDuplicateExtra(@Nullable Parcelable original, @NonNull String extraName) {
+ if (original != null && extras.getParcelable(extraName) != null) {
+ extras.putParcelable(extraName, original);
+ }
+ }
+
+ /**
* Sets the {@link #contentView} field to be a view with the standard "Latest Event"
* layout.
*
diff --git a/core/java/android/app/ProfilerInfo.java b/core/java/android/app/ProfilerInfo.java
index fad4798..d523427 100644
--- a/core/java/android/app/ProfilerInfo.java
+++ b/core/java/android/app/ProfilerInfo.java
@@ -22,6 +22,7 @@
import android.util.Slog;
import java.io.IOException;
+import java.util.Objects;
/**
* System private API for passing profiler settings.
@@ -132,4 +133,32 @@
streamingOutput = in.readInt() != 0;
agent = in.readString();
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final ProfilerInfo other = (ProfilerInfo) o;
+ // TODO: Also check #profileFd for equality.
+ return Objects.equals(profileFile, other.profileFile)
+ && autoStopProfiler == other.autoStopProfiler
+ && samplingInterval == other.samplingInterval
+ && streamingOutput == other.streamingOutput
+ && Objects.equals(agent, other.agent);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + Objects.hashCode(profileFile);
+ result = 31 * result + samplingInterval;
+ result = 31 * result + (autoStopProfiler ? 1 : 0);
+ result = 31 * result + (streamingOutput ? 1 : 0);
+ result = 31 * result + Objects.hashCode(agent);
+ return result;
+ }
}
diff --git a/core/java/android/app/ResultInfo.java b/core/java/android/app/ResultInfo.java
index 5e0867c..d5af08a 100644
--- a/core/java/android/app/ResultInfo.java
+++ b/core/java/android/app/ResultInfo.java
@@ -20,6 +20,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
+
/**
* {@hide}
*/
@@ -79,4 +81,29 @@
mData = null;
}
}
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || !(obj instanceof ResultInfo)) {
+ return false;
+ }
+ final ResultInfo other = (ResultInfo) obj;
+ final boolean intentsEqual = mData == null ? (other.mData == null)
+ : mData.filterEquals(other.mData);
+ return intentsEqual && Objects.equals(mResultWho, other.mResultWho)
+ && mResultCode == other.mResultCode
+ && mRequestCode == other.mRequestCode;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + mRequestCode;
+ result = 31 * result + mResultCode;
+ result = 31 * result + Objects.hashCode(mResultWho);
+ if (mData != null) {
+ result = 31 * result + mData.filterHashCode();
+ }
+ return result;
+ }
}
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java
index 6ea0825..6dca400 100644
--- a/core/java/android/app/SharedPreferencesImpl.java
+++ b/core/java/android/app/SharedPreferencesImpl.java
@@ -34,8 +34,6 @@
import libcore.io.IoUtils;
-import com.google.android.collect.Maps;
-
import org.xmlpull.v1.XmlPullParserException;
import java.io.BufferedInputStream;
@@ -52,6 +50,11 @@
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
final class SharedPreferencesImpl implements SharedPreferences {
private static final String TAG = "SharedPreferencesImpl";
@@ -71,16 +74,12 @@
private final Object mLock = new Object();
private final Object mWritingToDiskLock = new Object();
- @GuardedBy("mLock")
- private Map<String, Object> mMap;
+ private Future<Map<String, Object>> mMap;
@GuardedBy("mLock")
private int mDiskWritesInFlight = 0;
@GuardedBy("mLock")
- private boolean mLoaded = false;
-
- @GuardedBy("mLock")
private StructTimespec mStatTimestamp;
@GuardedBy("mLock")
@@ -107,27 +106,18 @@
mFile = file;
mBackupFile = makeBackupFile(file);
mMode = mode;
- mLoaded = false;
mMap = null;
startLoadFromDisk();
}
private void startLoadFromDisk() {
- synchronized (mLock) {
- mLoaded = false;
- }
- new Thread("SharedPreferencesImpl-load") {
- public void run() {
- loadFromDisk();
- }
- }.start();
+ FutureTask<Map<String, Object>> futureTask = new FutureTask<>(() -> loadFromDisk());
+ mMap = futureTask;
+ new Thread(futureTask, "SharedPreferencesImpl-load").start();
}
- private void loadFromDisk() {
+ private Map<String, Object> loadFromDisk() {
synchronized (mLock) {
- if (mLoaded) {
- return;
- }
if (mBackupFile.exists()) {
mFile.delete();
mBackupFile.renameTo(mFile);
@@ -139,7 +129,7 @@
Log.w(TAG, "Attempt to read preferences file " + mFile + " without permission");
}
- Map map = null;
+ Map<String, Object> map = null;
StructStat stat = null;
try {
stat = Os.stat(mFile.getPath());
@@ -148,7 +138,7 @@
try {
str = new BufferedInputStream(
new FileInputStream(mFile), 16*1024);
- map = XmlUtils.readMapXml(str);
+ map = (Map<String, Object>) XmlUtils.readMapXml(str);
} catch (Exception e) {
Log.w(TAG, "Cannot read " + mFile.getAbsolutePath(), e);
} finally {
@@ -160,16 +150,14 @@
}
synchronized (mLock) {
- mLoaded = true;
if (map != null) {
- mMap = map;
mStatTimestamp = stat.st_mtim;
mStatSize = stat.st_size;
} else {
- mMap = new HashMap<>();
+ map = new HashMap<>();
}
- mLock.notifyAll();
}
+ return map;
}
static File makeBackupFile(File prefsFile) {
@@ -214,106 +202,122 @@
}
}
+ @Override
public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
synchronized(mLock) {
mListeners.put(listener, CONTENT);
}
}
+ @Override
public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
synchronized(mLock) {
mListeners.remove(listener);
}
}
- private void awaitLoadedLocked() {
- if (!mLoaded) {
+ private @GuardedBy("mLock") Map<String, Object> getLoaded() {
+ // For backwards compatibility, we need to ignore any interrupts. b/70122540.
+ for (;;) {
+ try {
+ return mMap.get();
+ } catch (ExecutionException e) {
+ throw new IllegalStateException(e);
+ } catch (InterruptedException e) {
+ // Ignore and try again.
+ }
+ }
+ }
+ private @GuardedBy("mLock") Map<String, Object> getLoadedWithBlockGuard() {
+ if (!mMap.isDone()) {
// Raise an explicit StrictMode onReadFromDisk for this
// thread, since the real read will be in a different
// thread and otherwise ignored by StrictMode.
BlockGuard.getThreadPolicy().onReadFromDisk();
}
- while (!mLoaded) {
- try {
- mLock.wait();
- } catch (InterruptedException unused) {
- }
- }
+ return getLoaded();
}
+ @Override
public Map<String, ?> getAll() {
+ Map<String, Object> map = getLoadedWithBlockGuard();
synchronized (mLock) {
- awaitLoadedLocked();
- //noinspection unchecked
- return new HashMap<String, Object>(mMap);
+ return new HashMap<String, Object>(map);
}
}
+ @Override
@Nullable
public String getString(String key, @Nullable String defValue) {
+ Map<String, Object> map = getLoadedWithBlockGuard();
synchronized (mLock) {
- awaitLoadedLocked();
- String v = (String)mMap.get(key);
+ String v = (String) map.get(key);
return v != null ? v : defValue;
}
}
+ @Override
@Nullable
public Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
+ Map<String, Object> map = getLoadedWithBlockGuard();
synchronized (mLock) {
- awaitLoadedLocked();
- Set<String> v = (Set<String>) mMap.get(key);
+ @SuppressWarnings("unchecked")
+ Set<String> v = (Set<String>) map.get(key);
return v != null ? v : defValues;
}
}
+ @Override
public int getInt(String key, int defValue) {
+ Map<String, Object> map = getLoadedWithBlockGuard();
synchronized (mLock) {
- awaitLoadedLocked();
- Integer v = (Integer)mMap.get(key);
+ Integer v = (Integer) map.get(key);
return v != null ? v : defValue;
}
}
+ @Override
public long getLong(String key, long defValue) {
+ Map<String, Object> map = getLoadedWithBlockGuard();
synchronized (mLock) {
- awaitLoadedLocked();
- Long v = (Long)mMap.get(key);
+ Long v = (Long) map.get(key);
return v != null ? v : defValue;
}
}
+ @Override
public float getFloat(String key, float defValue) {
+ Map<String, Object> map = getLoadedWithBlockGuard();
synchronized (mLock) {
- awaitLoadedLocked();
- Float v = (Float)mMap.get(key);
+ Float v = (Float) map.get(key);
return v != null ? v : defValue;
}
}
+ @Override
public boolean getBoolean(String key, boolean defValue) {
+ Map<String, Object> map = getLoadedWithBlockGuard();
synchronized (mLock) {
- awaitLoadedLocked();
- Boolean v = (Boolean)mMap.get(key);
+ Boolean v = (Boolean) map.get(key);
return v != null ? v : defValue;
}
}
+ @Override
public boolean contains(String key) {
+ Map<String, Object> map = getLoadedWithBlockGuard();
synchronized (mLock) {
- awaitLoadedLocked();
- return mMap.containsKey(key);
+ return map.containsKey(key);
}
}
+ @Override
public Editor edit() {
- // TODO: remove the need to call awaitLoadedLocked() when
+ // TODO: remove the need to call getLoaded() when
// requesting an editor. will require some work on the
// Editor, but then we should be able to do:
//
// context.getSharedPreferences(..).edit().putString(..).apply()
//
// ... all without blocking.
- synchronized (mLock) {
- awaitLoadedLocked();
- }
+ getLoadedWithBlockGuard();
return new EditorImpl();
}
@@ -347,71 +351,81 @@
}
public final class EditorImpl implements Editor {
- private final Object mLock = new Object();
+ private final Object mEditorLock = new Object();
- @GuardedBy("mLock")
- private final Map<String, Object> mModified = Maps.newHashMap();
+ @GuardedBy("mEditorLock")
+ private final Map<String, Object> mModified = new HashMap<>();
- @GuardedBy("mLock")
+ @GuardedBy("mEditorLock")
private boolean mClear = false;
+ @Override
public Editor putString(String key, @Nullable String value) {
- synchronized (mLock) {
+ synchronized (mEditorLock) {
mModified.put(key, value);
return this;
}
}
+ @Override
public Editor putStringSet(String key, @Nullable Set<String> values) {
- synchronized (mLock) {
+ synchronized (mEditorLock) {
mModified.put(key,
(values == null) ? null : new HashSet<String>(values));
return this;
}
}
+ @Override
public Editor putInt(String key, int value) {
- synchronized (mLock) {
+ synchronized (mEditorLock) {
mModified.put(key, value);
return this;
}
}
+ @Override
public Editor putLong(String key, long value) {
- synchronized (mLock) {
+ synchronized (mEditorLock) {
mModified.put(key, value);
return this;
}
}
+ @Override
public Editor putFloat(String key, float value) {
- synchronized (mLock) {
+ synchronized (mEditorLock) {
mModified.put(key, value);
return this;
}
}
+ @Override
public Editor putBoolean(String key, boolean value) {
- synchronized (mLock) {
+ synchronized (mEditorLock) {
mModified.put(key, value);
return this;
}
}
+ @Override
public Editor remove(String key) {
- synchronized (mLock) {
+ synchronized (mEditorLock) {
mModified.put(key, this);
return this;
}
}
+ @Override
public Editor clear() {
- synchronized (mLock) {
+ synchronized (mEditorLock) {
mClear = true;
return this;
}
}
+ @Override
public void apply() {
final long startTime = System.currentTimeMillis();
final MemoryCommitResult mcr = commitToMemory();
final Runnable awaitCommit = new Runnable() {
+ @Override
public void run() {
try {
mcr.writtenToDiskLatch.await();
@@ -429,6 +443,7 @@
QueuedWork.addFinisher(awaitCommit);
Runnable postWriteRunnable = new Runnable() {
+ @Override
public void run() {
awaitCommit.run();
QueuedWork.removeFinisher(awaitCommit);
@@ -456,13 +471,43 @@
// a memory commit comes in when we're already
// writing to disk.
if (mDiskWritesInFlight > 0) {
- // We can't modify our mMap as a currently
+ // We can't modify our map as a currently
// in-flight write owns it. Clone it before
// modifying it.
// noinspection unchecked
- mMap = new HashMap<String, Object>(mMap);
+ mMap = new Future<Map<String, Object>>() {
+ private Map<String, Object> mCopiedMap =
+ new HashMap<String, Object>(getLoaded());
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return false;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return false;
+ }
+
+ @Override
+ public boolean isDone() {
+ return true;
+ }
+
+ @Override
+ public Map<String, Object> get()
+ throws InterruptedException, ExecutionException {
+ return mCopiedMap;
+ }
+
+ @Override
+ public Map<String, Object> get(long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ return mCopiedMap;
+ }
+ };
}
- mapToWriteToDisk = mMap;
+ mapToWriteToDisk = getLoaded();
mDiskWritesInFlight++;
boolean hasListeners = mListeners.size() > 0;
@@ -471,13 +516,13 @@
listeners = new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
}
- synchronized (mLock) {
+ synchronized (mEditorLock) {
boolean changesMade = false;
if (mClear) {
- if (!mMap.isEmpty()) {
+ if (!mapToWriteToDisk.isEmpty()) {
changesMade = true;
- mMap.clear();
+ mapToWriteToDisk.clear();
}
mClear = false;
}
@@ -489,18 +534,18 @@
// setting a value to "null" for a given key is specified to be
// equivalent to calling remove on that key.
if (v == this || v == null) {
- if (!mMap.containsKey(k)) {
+ if (!mapToWriteToDisk.containsKey(k)) {
continue;
}
- mMap.remove(k);
+ mapToWriteToDisk.remove(k);
} else {
- if (mMap.containsKey(k)) {
- Object existingValue = mMap.get(k);
+ if (mapToWriteToDisk.containsKey(k)) {
+ Object existingValue = mapToWriteToDisk.get(k);
if (existingValue != null && existingValue.equals(v)) {
continue;
}
}
- mMap.put(k, v);
+ mapToWriteToDisk.put(k, v);
}
changesMade = true;
@@ -522,6 +567,7 @@
mapToWriteToDisk);
}
+ @Override
public boolean commit() {
long startTime = 0;
@@ -564,11 +610,7 @@
}
} else {
// Run this function on the main thread.
- ActivityThread.sMainThreadHandler.post(new Runnable() {
- public void run() {
- notifyListeners(mcr);
- }
- });
+ ActivityThread.sMainThreadHandler.post(() -> notifyListeners(mcr));
}
}
}
@@ -594,6 +636,7 @@
final boolean isFromSyncCommit = (postWriteRunnable == null);
final Runnable writeToDiskRunnable = new Runnable() {
+ @Override
public void run() {
synchronized (mWritingToDiskLock) {
writeToFile(mcr, isFromSyncCommit);
@@ -646,7 +689,7 @@
return str;
}
- // Note: must hold mWritingToDiskLock
+ @GuardedBy("mWritingToDiskLock")
private void writeToFile(MemoryCommitResult mcr, boolean isFromSyncCommit) {
long startTime = 0;
long existsTime = 0;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index e48946f..f831ae2 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -22,6 +22,7 @@
import android.app.admin.IDevicePolicyManager;
import android.app.job.IJobScheduler;
import android.app.job.JobScheduler;
+import android.app.slice.SliceManager;
import android.app.timezone.RulesManager;
import android.app.trust.TrustManager;
import android.app.usage.IStorageStatsManager;
@@ -944,6 +945,16 @@
ICrossProfileApps.Stub.asInterface(b));
}
});
+
+ registerService(Context.SLICE_SERVICE, SliceManager.class,
+ new CachedServiceFetcher<SliceManager>() {
+ @Override
+ public SliceManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ return new SliceManager(ctx.getOuterContext(),
+ ctx.mMainThread.getHandler());
+ }
+ });
}
/**
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index c99de5d..8f01685 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -26,6 +26,7 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
+import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManagerGlobal;
import android.os.IBinder;
@@ -690,42 +691,15 @@
.getRealDisplay(Display.DEFAULT_DISPLAY);
Point displaySize = new Point();
display.getRealSize(displaySize);
- final int displayWidth = displaySize.x;
- final int displayHeight = displaySize.y;
- final float screenshotWidth;
- final float screenshotHeight;
-
- final int rotation = display.getRotation();
- switch (rotation) {
- case ROTATION_FREEZE_0: {
- screenshotWidth = displayWidth;
- screenshotHeight = displayHeight;
- } break;
- case ROTATION_FREEZE_90: {
- screenshotWidth = displayHeight;
- screenshotHeight = displayWidth;
- } break;
- case ROTATION_FREEZE_180: {
- screenshotWidth = displayWidth;
- screenshotHeight = displayHeight;
- } break;
- case ROTATION_FREEZE_270: {
- screenshotWidth = displayHeight;
- screenshotHeight = displayWidth;
- } break;
- default: {
- throw new IllegalArgumentException("Invalid rotation: "
- + rotation);
- }
- }
+ int rotation = display.getRotation();
// Take the screenshot
Bitmap screenShot = null;
try {
// Calling out without a lock held.
- screenShot = mUiAutomationConnection.takeScreenshot((int) screenshotWidth,
- (int) screenshotHeight);
+ screenShot = mUiAutomationConnection.takeScreenshot(
+ new Rect(0, 0, displaySize.x, displaySize.y), rotation);
if (screenShot == null) {
return null;
}
@@ -734,21 +708,6 @@
return null;
}
- // Rotate the screenshot to the current orientation
- if (rotation != ROTATION_FREEZE_0) {
- Bitmap unrotatedScreenShot = Bitmap.createBitmap(displayWidth, displayHeight,
- Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(unrotatedScreenShot);
- canvas.translate(unrotatedScreenShot.getWidth() / 2,
- unrotatedScreenShot.getHeight() / 2);
- canvas.rotate(getDegreesForRotation(rotation));
- canvas.translate(- screenshotWidth / 2, - screenshotHeight / 2);
- canvas.drawBitmap(screenShot, 0, 0, null);
- canvas.setBitmap(null);
- screenShot.recycle();
- screenShot = unrotatedScreenShot;
- }
-
// Optimization
screenShot.setHasAlpha(false);
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 5e414b8..d3828ab 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.pm.IPackageManager;
import android.graphics.Bitmap;
+import android.graphics.Rect;
import android.hardware.input.InputManager;
import android.os.Binder;
import android.os.IBinder;
@@ -153,7 +154,7 @@
}
@Override
- public Bitmap takeScreenshot(int width, int height) {
+ public Bitmap takeScreenshot(Rect crop, int rotation) {
synchronized (mLock) {
throwIfCalledByNotTrustedUidLocked();
throwIfShutdownLocked();
@@ -161,7 +162,9 @@
}
final long identity = Binder.clearCallingIdentity();
try {
- return SurfaceControl.screenshot(width, height);
+ int width = crop.width();
+ int height = crop.height();
+ return SurfaceControl.screenshot(crop, width, height, rotation);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java
index 392387a..61b90e1 100644
--- a/core/java/android/app/VrManager.java
+++ b/core/java/android/app/VrManager.java
@@ -4,6 +4,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.content.ComponentName;
import android.content.Context;
import android.os.Handler;
@@ -214,4 +215,22 @@
e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Start VR Input method for the packageName in {@link ComponentName}.
+ * This method notifies InputMethodManagerService to use VR IME instead of
+ * regular phone IME.
+ * @param componentName ComponentName of a VR InputMethod that should be set as selected
+ * input by InputMethodManagerService.
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
+ public void setVrInputMethod(ComponentName componentName) {
+ try {
+ mService.setVrInputMethod(componentName);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/admin/ConnectEvent.java b/core/java/android/app/admin/ConnectEvent.java
index ffd38e2..f06a925 100644
--- a/core/java/android/app/admin/ConnectEvent.java
+++ b/core/java/android/app/admin/ConnectEvent.java
@@ -32,29 +32,30 @@
public final class ConnectEvent extends NetworkEvent implements Parcelable {
/** The destination IP address. */
- private final String ipAddress;
+ private final String mIpAddress;
/** The destination port number. */
- private final int port;
+ private final int mPort;
/** @hide */
public ConnectEvent(String ipAddress, int port, String packageName, long timestamp) {
super(packageName, timestamp);
- this.ipAddress = ipAddress;
- this.port = port;
+ this.mIpAddress = ipAddress;
+ this.mPort = port;
}
private ConnectEvent(Parcel in) {
- this.ipAddress = in.readString();
- this.port = in.readInt();
- this.packageName = in.readString();
- this.timestamp = in.readLong();
+ this.mIpAddress = in.readString();
+ this.mPort = in.readInt();
+ this.mPackageName = in.readString();
+ this.mTimestamp = in.readLong();
+ this.mId = in.readLong();
}
public InetAddress getInetAddress() {
try {
// ipAddress is already an address, not a host name, no DNS resolution will happen.
- return InetAddress.getByName(ipAddress);
+ return InetAddress.getByName(mIpAddress);
} catch (UnknownHostException e) {
// Should never happen as we aren't passing a host name.
return InetAddress.getLoopbackAddress();
@@ -62,13 +63,13 @@
}
public int getPort() {
- return port;
+ return mPort;
}
@Override
public String toString() {
- return String.format("ConnectEvent(%s, %d, %d, %s)", ipAddress, port, timestamp,
- packageName);
+ return String.format("ConnectEvent(%s, %d, %d, %s)", mIpAddress, mPort, mTimestamp,
+ mPackageName);
}
public static final Parcelable.Creator<ConnectEvent> CREATOR
@@ -96,10 +97,10 @@
public void writeToParcel(Parcel out, int flags) {
// write parcel token first
out.writeInt(PARCEL_TOKEN_CONNECT_EVENT);
- out.writeString(ipAddress);
- out.writeInt(port);
- out.writeString(packageName);
- out.writeLong(timestamp);
+ out.writeString(mIpAddress);
+ out.writeInt(mPort);
+ out.writeString(mPackageName);
+ out.writeLong(mTimestamp);
+ out.writeLong(mId);
}
}
-
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 0bca969..562b981 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -57,7 +57,12 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.ContactsContract.Directory;
+import android.security.AttestedKeyPair;
import android.security.Credentials;
+import android.security.KeyChain;
+import android.security.KeyChainException;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.ParcelableKeyGenParameterSpec;
import android.service.restrictions.RestrictionsReceiver;
import android.telephony.TelephonyManager;
import android.util.ArraySet;
@@ -75,6 +80,7 @@
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.security.KeyFactory;
+import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
@@ -3943,6 +3949,50 @@
}
/**
+ * Called by a device or profile owner, or delegated certificate installer, to generate a
+ * new private/public key pair. If the device supports key generation via secure hardware,
+ * this method is useful for creating a key in KeyChain that never left the secure hardware.
+ *
+ * Access to the key is controlled the same way as in {@link #installKeyPair}.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if calling from a delegated certificate installer.
+ * @param algorithm The key generation algorithm, see {@link java.security.KeyPairGenerator}.
+ * @param keySpec Specification of the key to generate, see
+ * {@link java.security.KeyPairGenerator}.
+ * @return A non-null {@code AttestedKeyPair} if the key generation succeeded, null otherwise.
+ * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
+ * owner.
+ * @throws IllegalArgumentException if the alias in {@code keySpec} is empty, or if the
+ * algorithm specification in {@code keySpec} is not {@code RSAKeyGenParameterSpec}
+ * or {@code ECGenParameterSpec}.
+ */
+ public AttestedKeyPair generateKeyPair(@Nullable ComponentName admin,
+ @NonNull String algorithm, @NonNull KeyGenParameterSpec keySpec) {
+ throwIfParentInstance("generateKeyPair");
+ try {
+ final ParcelableKeyGenParameterSpec parcelableSpec =
+ new ParcelableKeyGenParameterSpec(keySpec);
+ final boolean success = mService.generateKeyPair(
+ admin, mContext.getPackageName(), algorithm, parcelableSpec);
+ if (!success) {
+ Log.e(TAG, "Error generating key via DevicePolicyManagerService.");
+ return null;
+ }
+
+ final KeyPair keyPair = KeyChain.getKeyPair(mContext, keySpec.getKeystoreAlias());
+ return new AttestedKeyPair(keyPair, null);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } catch (KeyChainException e) {
+ Log.w(TAG, "Failed to generate key", e);
+ } catch (InterruptedException e) {
+ Log.w(TAG, "Interrupted while generating key", e);
+ Thread.currentThread().interrupt();
+ }
+ return null;
+ }
+
+ /**
* @return the alias of a given CA certificate in the certificate store, or {@code null} if it
* doesn't exist.
*/
@@ -6219,7 +6269,7 @@
* @return {@code true} if the user was removed, {@code false} otherwise.
* @throws SecurityException if {@code admin} is not a device owner.
*/
- public boolean removeUser(@NonNull ComponentName admin, UserHandle userHandle) {
+ public boolean removeUser(@NonNull ComponentName admin, @NonNull UserHandle userHandle) {
throwIfParentInstance("removeUser");
try {
return mService.removeUser(admin, userHandle);
@@ -6230,6 +6280,7 @@
/**
* Called by a device owner to switch the specified user to the foreground.
+ * <p> This cannot be used to switch to a managed profile.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param userHandle the user to switch to; null will switch to primary.
@@ -6247,6 +6298,65 @@
}
/**
+ * Called by a device owner to stop the specified secondary user.
+ * <p> This cannot be used to stop the primary user or a managed profile.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param userHandle the user to be stopped.
+ * @return {@code true} if the user can be stopped, {@code false} otherwise.
+ * @throws SecurityException if {@code admin} is not a device owner.
+ */
+ public boolean stopUser(@NonNull ComponentName admin, @NonNull UserHandle userHandle) {
+ throwIfParentInstance("stopUser");
+ try {
+ return mService.stopUser(admin, userHandle);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Called by a profile owner that is affiliated with the device owner to stop the calling user
+ * and switch back to primary.
+ * <p> This has no effect when called on a managed profile.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @return {@code true} if the exit was successful, {@code false} otherwise.
+ * @throws SecurityException if {@code admin} is not a profile owner affiliated with the device
+ * owner.
+ */
+ public boolean logoutUser(@NonNull ComponentName admin) {
+ throwIfParentInstance("logoutUser");
+ try {
+ return mService.logoutUser(admin);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Called by a device owner to list all secondary users on the device, excluding managed
+ * profiles.
+ * <p> Used for various user management APIs, including {@link #switchUser}, {@link #removeUser}
+ * and {@link #stopUser}.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @return list of other {@link UserHandle}s on the device.
+ * @throws SecurityException if {@code admin} is not a device owner.
+ * @see #switchUser
+ * @see #removeUser
+ * @see #stopUser
+ */
+ public List<UserHandle> getSecondaryUsers(@NonNull ComponentName admin) {
+ throwIfParentInstance("getSecondaryUsers");
+ try {
+ return mService.getSecondaryUsers(admin);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Retrieves the application restrictions for a given target application running in the calling
* user.
* <p>
@@ -6667,7 +6777,7 @@
}
/**
- * Called by device owners to update {@link android.provider.Settings.Global} settings.
+ * Called by device owner to update {@link android.provider.Settings.Global} settings.
* Validation that the value of the setting is in the correct form for the setting type should
* be performed by the caller.
* <p>
@@ -6716,6 +6826,37 @@
}
/**
+ * Called by device owner to update {@link android.provider.Settings.System} settings.
+ * Validation that the value of the setting is in the correct form for the setting type should
+ * be performed by the caller.
+ * <p>
+ * The settings that can be updated with this method are:
+ * <ul>
+ * <li>{@link android.provider.Settings.System#SCREEN_BRIGHTNESS}</li>
+ * <li>{@link android.provider.Settings.System#SCREEN_BRIGHTNESS_MODE}</li>
+ * <li>{@link android.provider.Settings.System#SCREEN_OFF_TIMEOUT}</li>
+ * </ul>
+ * <p>
+ *
+ * @see android.provider.Settings.System#SCREEN_OFF_TIMEOUT
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param setting The name of the setting to update.
+ * @param value The value to update the setting to.
+ * @throws SecurityException if {@code admin} is not a device owner.
+ */
+ public void setSystemSetting(@NonNull ComponentName admin, @NonNull String setting,
+ String value) {
+ throwIfParentInstance("setSystemSetting");
+ if (mService != null) {
+ try {
+ mService.setSystemSetting(admin, setting, value);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
* Called by device owner to set the system wall clock time. This only takes effect if called
* when {@link android.provider.Settings.Global#AUTO_TIME} is 0, otherwise {@code false} will be
* returned.
@@ -8444,6 +8585,38 @@
}
/**
+ * Called by a device owner to specify whether a logout button is enabled for all secondary
+ * users. The system may show a logout button that stops the user and switches back to the
+ * primary user.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param enabled whether logout button should be enabled or not.
+ * @throws SecurityException if {@code admin} is not a device owner.
+ */
+ public void setLogoutButtonEnabled(@NonNull ComponentName admin, boolean enabled) {
+ throwIfParentInstance("setLogoutButtonEnabled");
+ try {
+ mService.setLogoutButtonEnabled(admin, enabled);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether logout button is enabled by a device owner.
+ *
+ * @return {@code true} if logout button is enabled by device owner, {@code false} otherwise.
+ */
+ public boolean isLogoutButtonEnabled() {
+ throwIfParentInstance("isLogoutButtonEnabled");
+ try {
+ return mService.isLogoutButtonEnabled();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Callback used in {@link #clearApplicationUserData}
* to indicate that the clearing of an application's user data is done.
*/
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index eef2f98..05f6c2a 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -101,4 +101,18 @@
* not enforced by the profile/device owner.
*/
public abstract Intent createUserRestrictionSupportIntent(int userId, String userRestriction);
+
+ /**
+ * Returns whether this user/profile is affiliated with the device.
+ *
+ * <p>
+ * By definition, the user that the device owner runs on is always affiliated with the device.
+ * Any other user/profile is considered affiliated with the device if the set specified by its
+ * profile owner via {@link DevicePolicyManager#setAffiliationIds} intersects with the device
+ * owner's.
+ * <p>
+ * Profile owner on the primary user will never be considered as affiliated as there is no
+ * device owner to be affiliated with.
+ */
+ public abstract boolean isUserAffiliatedWithDevice(int userId);
}
diff --git a/core/java/android/app/admin/DnsEvent.java b/core/java/android/app/admin/DnsEvent.java
index f84c5b0..4ddf13e 100644
--- a/core/java/android/app/admin/DnsEvent.java
+++ b/core/java/android/app/admin/DnsEvent.java
@@ -34,46 +34,47 @@
public final class DnsEvent extends NetworkEvent implements Parcelable {
/** The hostname that was looked up. */
- private final String hostname;
+ private final String mHostname;
/** Contains (possibly a subset of) the IP addresses returned. */
- private final String[] ipAddresses;
+ private final String[] mIpAddresses;
/**
* The number of IP addresses returned from the DNS lookup event. May be different from the
* length of ipAddresses if there were too many addresses to log.
*/
- private final int ipAddressesCount;
+ private final int mIpAddressesCount;
/** @hide */
public DnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount,
String packageName, long timestamp) {
super(packageName, timestamp);
- this.hostname = hostname;
- this.ipAddresses = ipAddresses;
- this.ipAddressesCount = ipAddressesCount;
+ this.mHostname = hostname;
+ this.mIpAddresses = ipAddresses;
+ this.mIpAddressesCount = ipAddressesCount;
}
private DnsEvent(Parcel in) {
- this.hostname = in.readString();
- this.ipAddresses = in.createStringArray();
- this.ipAddressesCount = in.readInt();
- this.packageName = in.readString();
- this.timestamp = in.readLong();
+ this.mHostname = in.readString();
+ this.mIpAddresses = in.createStringArray();
+ this.mIpAddressesCount = in.readInt();
+ this.mPackageName = in.readString();
+ this.mTimestamp = in.readLong();
+ this.mId = in.readLong();
}
/** Returns the hostname that was looked up. */
public String getHostname() {
- return hostname;
+ return mHostname;
}
/** Returns (possibly a subset of) the IP addresses returned. */
public List<InetAddress> getInetAddresses() {
- if (ipAddresses == null || ipAddresses.length == 0) {
+ if (mIpAddresses == null || mIpAddresses.length == 0) {
return Collections.emptyList();
}
- final List<InetAddress> inetAddresses = new ArrayList<>(ipAddresses.length);
- for (final String ipAddress : ipAddresses) {
+ final List<InetAddress> inetAddresses = new ArrayList<>(mIpAddresses.length);
+ for (final String ipAddress : mIpAddresses) {
try {
// ipAddress is already an address, not a host name, no DNS resolution will happen.
inetAddresses.add(InetAddress.getByName(ipAddress));
@@ -90,14 +91,14 @@
* addresses to log.
*/
public int getTotalResolvedAddressCount() {
- return ipAddressesCount;
+ return mIpAddressesCount;
}
@Override
public String toString() {
- return String.format("DnsEvent(%s, %s, %d, %d, %s)", hostname,
- (ipAddresses == null) ? "NONE" : String.join(" ", ipAddresses),
- ipAddressesCount, timestamp, packageName);
+ return String.format("DnsEvent(%s, %s, %d, %d, %s)", mHostname,
+ (mIpAddresses == null) ? "NONE" : String.join(" ", mIpAddresses),
+ mIpAddressesCount, mTimestamp, mPackageName);
}
public static final Parcelable.Creator<DnsEvent> CREATOR
@@ -125,11 +126,11 @@
public void writeToParcel(Parcel out, int flags) {
// write parcel token first
out.writeInt(PARCEL_TOKEN_DNS_EVENT);
- out.writeString(hostname);
- out.writeStringArray(ipAddresses);
- out.writeInt(ipAddressesCount);
- out.writeString(packageName);
- out.writeLong(timestamp);
+ out.writeString(mHostname);
+ out.writeStringArray(mIpAddresses);
+ out.writeInt(mIpAddressesCount);
+ out.writeString(mPackageName);
+ out.writeLong(mTimestamp);
+ out.writeLong(mId);
}
}
-
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index b7740e9..c525df7 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -36,6 +36,7 @@
import android.os.PersistableBundle;
import android.os.RemoteCallback;
import android.os.UserHandle;
+import android.security.keystore.ParcelableKeyGenParameterSpec;
import java.util.List;
@@ -165,6 +166,7 @@
in byte[] certBuffer, in byte[] certChainBuffer, String alias, boolean requestAccess,
boolean isUserSelectable);
boolean removeKeyPair(in ComponentName who, in String callerPackage, String alias);
+ boolean generateKeyPair(in ComponentName who, in String callerPackage, in String algorithm, in ParcelableKeyGenParameterSpec keySpec);
void choosePrivateKeyAlias(int uid, in Uri uri, in String alias, IBinder aliasCallback);
void setDelegatedScopes(in ComponentName who, in String delegatePackage, in List<String> scopes);
@@ -215,6 +217,9 @@
UserHandle createAndManageUser(in ComponentName who, in String name, in ComponentName profileOwner, in PersistableBundle adminExtras, in int flags);
boolean removeUser(in ComponentName who, in UserHandle userHandle);
boolean switchUser(in ComponentName who, in UserHandle userHandle);
+ boolean stopUser(in ComponentName who, in UserHandle userHandle);
+ boolean logoutUser(in ComponentName who);
+ List<UserHandle> getSecondaryUsers(in ComponentName who);
void enableSystemApp(in ComponentName admin, in String callerPackage, in String packageName);
int enableSystemAppWithIntent(in ComponentName admin, in String callerPackage, in Intent intent);
@@ -231,6 +236,7 @@
int getLockTaskFeatures(in ComponentName who);
void setGlobalSetting(in ComponentName who, in String setting, in String value);
+ void setSystemSetting(in ComponentName who, in String setting, in String value);
void setSecureSetting(in ComponentName who, in String setting, in String value);
boolean setTime(in ComponentName who, long millis);
@@ -365,4 +371,7 @@
StringParceledListSlice getOwnerInstalledCaCerts(in UserHandle user);
boolean clearApplicationUserData(in ComponentName admin, in String packageName, in IPackageDataObserver callback);
+
+ void setLogoutButtonEnabled(in ComponentName admin, boolean enabled);
+ boolean isLogoutButtonEnabled();
}
diff --git a/core/java/android/app/admin/NetworkEvent.java b/core/java/android/app/admin/NetworkEvent.java
index 2646c3f..947e4fe 100644
--- a/core/java/android/app/admin/NetworkEvent.java
+++ b/core/java/android/app/admin/NetworkEvent.java
@@ -18,8 +18,8 @@
import android.content.pm.PackageManager;
import android.os.Parcel;
-import android.os.Parcelable;
import android.os.ParcelFormatException;
+import android.os.Parcelable;
/**
* An abstract class that represents a network event.
@@ -32,10 +32,13 @@
static final int PARCEL_TOKEN_CONNECT_EVENT = 2;
/** The package name of the UID that performed the query. */
- String packageName;
+ String mPackageName;
/** The timestamp of the event being reported in milliseconds. */
- long timestamp;
+ long mTimestamp;
+
+ /** The id of the event. */
+ long mId;
/** @hide */
NetworkEvent() {
@@ -44,8 +47,8 @@
/** @hide */
NetworkEvent(String packageName, long timestamp) {
- this.packageName = packageName;
- this.timestamp = timestamp;
+ this.mPackageName = packageName;
+ this.mTimestamp = timestamp;
}
/**
@@ -53,7 +56,7 @@
* {@link PackageManager#getNameForUid}.
*/
public String getPackageName() {
- return packageName;
+ return mPackageName;
}
/**
@@ -61,7 +64,20 @@
* the time the event was reported and midnight, January 1, 1970 UTC.
*/
public long getTimestamp() {
- return timestamp;
+ return mTimestamp;
+ }
+
+ /** @hide */
+ public void setId(long id) {
+ this.mId = id;
+ }
+
+ /**
+ * Returns the id of the event, where the id monotonically increases for each event. The id
+ * is reset when the device reboots, and when network logging is enabled.
+ */
+ public long getId() {
+ return this.mId;
}
@Override
@@ -95,4 +111,3 @@
@Override
public abstract void writeToParcel(Parcel out, int flags);
}
-
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index da5569d..7b549cd5 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -2139,6 +2139,16 @@
return mActivityComponent;
}
+ /**
+ * Called by Autofill server when app forged a different value.
+ *
+ * @hide
+ */
+ public void setActivityComponent(ComponentName componentName) {
+ ensureData();
+ mActivityComponent = componentName;
+ }
+
/** @hide */
public int getFlags() {
return mFlags;
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 7aa80d2..861cb9a 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -263,6 +263,17 @@
ParcelFileDescriptor newState) throws IOException;
/**
+ * New version of {@link #onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor)}
+ * that handles a long app version code. Default implementation casts the version code to
+ * an int and calls {@link #onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor)}.
+ */
+ public void onRestore(BackupDataInput data, long appVersionCode,
+ ParcelFileDescriptor newState)
+ throws IOException {
+ onRestore(data, (int) appVersionCode, newState);
+ }
+
+ /**
* The application is having its entire file system contents backed up. {@code data}
* points to the backup destination, and the app has the opportunity to choose which
* files are to be stored. To commit a file as part of the backup, call the
@@ -947,7 +958,7 @@
}
@Override
- public void doRestore(ParcelFileDescriptor data, int appVersionCode,
+ public void doRestore(ParcelFileDescriptor data, long appVersionCode,
ParcelFileDescriptor newState,
int token, IBackupManager callbackBinder) throws RemoteException {
// Ensure that we're running with the app's normal permission level
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 9f9b217..6512b98 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -16,10 +16,12 @@
package android.app.backup;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -446,6 +448,57 @@
}
/**
+ * 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
+ * ignored. Only the host process of the transport can change its description, otherwise a
+ * {@link SecurityException} will be thrown.
+ *
+ * @param transportComponent The identity of the transport being described.
+ * @param name A {@link String} with the new name for the transport. This is NOT for
+ * identification. MUST NOT be {@code null}.
+ * @param configurationIntent An {@link Intent} that can be passed to
+ * {@link Context#startActivity} in order to launch the transport's configuration UI. It may
+ * be {@code null} if the transport does not offer any user-facing configuration UI.
+ * @param currentDestinationString A {@link String} describing the destination to which the
+ * transport is currently sending data. MUST NOT be {@code null}.
+ * @param dataManagementIntent An {@link Intent} that can be passed to
+ * {@link Context#startActivity} in order to launch the transport's data-management UI. It
+ * may be {@code null} if the transport does not offer any user-facing data
+ * management UI.
+ * @param dataManagementLabel A {@link String} to be used as the label for the transport's data
+ * management affordance. This MUST be {@code null} when dataManagementIntent is
+ * {@code null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
+ * @throws SecurityException If the UID of the calling process differs from the package UID of
+ * {@code transportComponent} or if the caller does NOT have BACKUP permission.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
+ public void updateTransportAttributes(
+ ComponentName transportComponent,
+ String name,
+ @Nullable Intent configurationIntent,
+ String currentDestinationString,
+ @Nullable Intent dataManagementIntent,
+ @Nullable String dataManagementLabel) {
+ checkServiceBinder();
+ if (sService != null) {
+ try {
+ sService.updateTransportAttributes(
+ transportComponent,
+ name,
+ configurationIntent,
+ currentDestinationString,
+ dataManagementIntent,
+ dataManagementLabel);
+ } catch (RemoteException e) {
+ Log.e(TAG, "describeTransport() couldn't connect");
+ }
+ }
+ }
+
+ /**
* Specify the current backup transport.
*
* @param transport The name of the transport to select. This should be one
diff --git a/core/java/android/app/backup/BackupManagerMonitor.java b/core/java/android/app/backup/BackupManagerMonitor.java
index ebad16e..ae4a98a 100644
--- a/core/java/android/app/backup/BackupManagerMonitor.java
+++ b/core/java/android/app/backup/BackupManagerMonitor.java
@@ -40,9 +40,14 @@
/** string : the package name */
public static final String EXTRA_LOG_EVENT_PACKAGE_NAME =
"android.app.backup.extra.LOG_EVENT_PACKAGE_NAME";
- /** int : the versionCode of the package named by EXTRA_LOG_EVENT_PACKAGE_NAME */
+ /** int : the versionCode of the package named by EXTRA_LOG_EVENT_PACKAGE_NAME
+ * @deprecated Use {@link #EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION} */
+ @Deprecated
public static final String EXTRA_LOG_EVENT_PACKAGE_VERSION =
"android.app.backup.extra.LOG_EVENT_PACKAGE_VERSION";
+ /** long : the full versionCode of the package named by EXTRA_LOG_EVENT_PACKAGE_NAME */
+ public static final String EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION =
+ "android.app.backup.extra.LOG_EVENT_PACKAGE_FULL_VERSION";
/** int : the id of the log message, will be a unique identifier */
public static final String EXTRA_LOG_EVENT_ID = "android.app.backup.extra.LOG_EVENT_ID";
/**
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index f1dc6d2..c42a898 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -222,6 +222,36 @@
IFullBackupRestoreObserver observer);
/**
+ * 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
+ * ignored. Only the host process of the transport can change its description, otherwise a
+ * {@link SecurityException} will be thrown.
+ *
+ * @param transportComponent The identity of the transport being described.
+ * @param name A {@link String} with the new name for the transport. This is NOT for
+ * identification. MUST NOT be {@code null}.
+ * @param configurationIntent An {@link Intent} that can be passed to
+ * {@link Context#startActivity} in order to launch the transport's configuration UI. It may
+ * be {@code null} if the transport does not offer any user-facing configuration UI.
+ * @param currentDestinationString A {@link String} describing the destination to which the
+ * transport is currently sending data. MUST NOT be {@code null}.
+ * @param dataManagementIntent An {@link Intent} that can be passed to
+ * {@link Context#startActivity} in order to launch the transport's data-management UI. It
+ * may be {@code null} if the transport does not offer any user-facing data
+ * management UI.
+ * @param dataManagementLabel A {@link String} to be used as the label for the transport's data
+ * management affordance. This MUST be {@code null} when dataManagementIntent is
+ * {@code null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
+ * @throws SecurityException If the UID of the calling process differs from the package UID of
+ * {@code transportComponent} or if the caller does NOT have BACKUP permission.
+ *
+ * @hide
+ */
+ void updateTransportAttributes(in ComponentName transportComponent, in String name,
+ in Intent configurationIntent, in String currentDestinationString,
+ in Intent dataManagementIntent, in String dataManagementLabel);
+
+ /**
* Identify the currently selected transport. Callers must hold the
* android.permission.BACKUP permission to use this method.
*/
diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
new file mode 100644
index 0000000..a2b7d58
--- /dev/null
+++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import static android.view.Display.INVALID_DISPLAY;
+
+import android.app.ClientTransactionHandler;
+import android.content.res.Configuration;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Trace;
+
+import java.util.Objects;
+
+/**
+ * Activity configuration changed callback.
+ * @hide
+ */
+public class ActivityConfigurationChangeItem extends ClientTransactionItem {
+
+ private Configuration mConfiguration;
+
+ @Override
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ // TODO(lifecycler): detect if PIP or multi-window mode changed and report it here.
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged");
+ client.handleActivityConfigurationChanged(token, mConfiguration, INVALID_DISPLAY);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+ }
+
+
+ // ObjectPoolItem implementation
+
+ private ActivityConfigurationChangeItem() {}
+
+ /** Obtain an instance initialized with provided params. */
+ public static ActivityConfigurationChangeItem obtain(Configuration config) {
+ ActivityConfigurationChangeItem instance =
+ ObjectPool.obtain(ActivityConfigurationChangeItem.class);
+ if (instance == null) {
+ instance = new ActivityConfigurationChangeItem();
+ }
+ instance.mConfiguration = config;
+
+ return instance;
+ }
+
+ @Override
+ public void recycle() {
+ mConfiguration = null;
+ ObjectPool.recycle(this);
+ }
+
+
+ // Parcelable implementation
+
+ /** Write to Parcel. */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeTypedObject(mConfiguration, flags);
+ }
+
+ /** Read from Parcel. */
+ private ActivityConfigurationChangeItem(Parcel in) {
+ mConfiguration = in.readTypedObject(Configuration.CREATOR);
+ }
+
+ public static final Creator<ActivityConfigurationChangeItem> CREATOR =
+ new Creator<ActivityConfigurationChangeItem>() {
+ public ActivityConfigurationChangeItem createFromParcel(Parcel in) {
+ return new ActivityConfigurationChangeItem(in);
+ }
+
+ public ActivityConfigurationChangeItem[] newArray(int size) {
+ return new ActivityConfigurationChangeItem[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final ActivityConfigurationChangeItem other = (ActivityConfigurationChangeItem) o;
+ return Objects.equals(mConfiguration, other.mConfiguration);
+ }
+
+ @Override
+ public int hashCode() {
+ return mConfiguration.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "ActivityConfigurationChange{config=" + mConfiguration + "}";
+ }
+}
diff --git a/core/java/android/app/servertransaction/ActivityLifecycleItem.java b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
new file mode 100644
index 0000000..24141e5
--- /dev/null
+++ b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Request for lifecycle state that an activity should reach.
+ * @hide
+ */
+public abstract class ActivityLifecycleItem extends ClientTransactionItem {
+
+ @IntDef({UNDEFINED, PRE_ON_CREATE, ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP,
+ ON_DESTROY, ON_RESTART})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LifecycleState{}
+ public static final int UNDEFINED = -1;
+ public static final int PRE_ON_CREATE = 0;
+ public static final int ON_CREATE = 1;
+ public static final int ON_START = 2;
+ public static final int ON_RESUME = 3;
+ public static final int ON_PAUSE = 4;
+ public static final int ON_STOP = 5;
+ public static final int ON_DESTROY = 6;
+ public static final int ON_RESTART = 7;
+
+ /** A final lifecycle state that an activity should reach. */
+ @LifecycleState
+ public abstract int getTargetState();
+}
diff --git a/core/java/android/app/servertransaction/ActivityResultItem.java b/core/java/android/app/servertransaction/ActivityResultItem.java
new file mode 100644
index 0000000..73b5ec4
--- /dev/null
+++ b/core/java/android/app/servertransaction/ActivityResultItem.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+
+import android.app.ClientTransactionHandler;
+import android.app.ResultInfo;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.Trace;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Activity result delivery callback.
+ * @hide
+ */
+public class ActivityResultItem extends ClientTransactionItem {
+
+ private List<ResultInfo> mResultInfoList;
+
+ @Override
+ public int getPreExecutionState() {
+ return ON_PAUSE;
+ }
+
+ @Override
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDeliverResult");
+ client.handleSendResult(token, mResultInfoList);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+ }
+
+
+ // ObjectPoolItem implementation
+
+ private ActivityResultItem() {}
+
+ /** Obtain an instance initialized with provided params. */
+ public static ActivityResultItem obtain(List<ResultInfo> resultInfoList) {
+ ActivityResultItem instance = ObjectPool.obtain(ActivityResultItem.class);
+ if (instance == null) {
+ instance = new ActivityResultItem();
+ }
+ instance.mResultInfoList = resultInfoList;
+
+ return instance;
+ }
+
+ @Override
+ public void recycle() {
+ mResultInfoList = null;
+ ObjectPool.recycle(this);
+ }
+
+
+ // Parcelable implementation
+
+ /** Write to Parcel. */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeTypedList(mResultInfoList, flags);
+ }
+
+ /** Read from Parcel. */
+ private ActivityResultItem(Parcel in) {
+ mResultInfoList = in.createTypedArrayList(ResultInfo.CREATOR);
+ }
+
+ public static final Parcelable.Creator<ActivityResultItem> CREATOR =
+ new Parcelable.Creator<ActivityResultItem>() {
+ public ActivityResultItem createFromParcel(Parcel in) {
+ return new ActivityResultItem(in);
+ }
+
+ public ActivityResultItem[] newArray(int size) {
+ return new ActivityResultItem[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final ActivityResultItem other = (ActivityResultItem) o;
+ return Objects.equals(mResultInfoList, other.mResultInfoList);
+ }
+
+ @Override
+ public int hashCode() {
+ return mResultInfoList.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "ActivityResultItem{resultInfoList=" + mResultInfoList + "}";
+ }
+}
diff --git a/core/java/android/app/servertransaction/BaseClientRequest.java b/core/java/android/app/servertransaction/BaseClientRequest.java
new file mode 100644
index 0000000..c91e0ca
--- /dev/null
+++ b/core/java/android/app/servertransaction/BaseClientRequest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import android.app.ClientTransactionHandler;
+import android.os.IBinder;
+
+/**
+ * Base interface for individual requests from server to client.
+ * Each of them can be prepared before scheduling and, eventually, executed.
+ * @hide
+ */
+public interface BaseClientRequest extends ObjectPoolItem {
+
+ /**
+ * Prepare the client request before scheduling.
+ * An example of this might be informing about pending updates for some values.
+ *
+ * @param client Target client handler.
+ * @param token Target activity token.
+ */
+ default void preExecute(ClientTransactionHandler client, IBinder token) {
+ }
+
+ /**
+ * Execute the request.
+ * @param client Target client handler.
+ * @param token Target activity token.
+ * @param pendingActions Container that may have data pending to be used.
+ */
+ void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions);
+
+ /**
+ * Perform all actions that need to happen after execution, e.g. report the result to server.
+ * @param client Target client handler.
+ * @param token Target activity token.
+ * @param pendingActions Container that may have data pending to be used.
+ */
+ default void postExecute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/core/java/android/app/servertransaction/ClientTransaction.aidl
similarity index 71%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to core/java/android/app/servertransaction/ClientTransaction.aidl
index 4ccdea5..ad8bcbf 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/core/java/android/app/servertransaction/ClientTransaction.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 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.
@@ -14,11 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+package android.app.servertransaction;
-import android.telephony.SubscriptionInfo;
-
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
-}
-
+/** @hide */
+parcelable ClientTransaction;
\ No newline at end of file
diff --git a/core/java/android/app/servertransaction/ClientTransaction.java b/core/java/android/app/servertransaction/ClientTransaction.java
new file mode 100644
index 0000000..764ceed
--- /dev/null
+++ b/core/java/android/app/servertransaction/ClientTransaction.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import android.annotation.Nullable;
+import android.app.ClientTransactionHandler;
+import android.app.IApplicationThread;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A container that holds a sequence of messages, which may be sent to a client.
+ * This includes a list of callbacks and a final lifecycle state.
+ *
+ * @see com.android.server.am.ClientLifecycleManager
+ * @see ClientTransactionItem
+ * @see ActivityLifecycleItem
+ * @hide
+ */
+public class ClientTransaction implements Parcelable, ObjectPoolItem {
+
+ /** A list of individual callbacks to a client. */
+ private List<ClientTransactionItem> mActivityCallbacks;
+
+ /**
+ * Final lifecycle state in which the client activity should be after the transaction is
+ * executed.
+ */
+ private ActivityLifecycleItem mLifecycleStateRequest;
+
+ /** Target client. */
+ private IApplicationThread mClient;
+
+ /** Target client activity. Might be null if the entire transaction is targeting an app. */
+ private IBinder mActivityToken;
+
+ /**
+ * Add a message to the end of the sequence of callbacks.
+ * @param activityCallback A single message that can contain a lifecycle request/callback.
+ */
+ public void addCallback(ClientTransactionItem activityCallback) {
+ if (mActivityCallbacks == null) {
+ mActivityCallbacks = new ArrayList<>();
+ }
+ mActivityCallbacks.add(activityCallback);
+ }
+
+ /** Get the list of callbacks. */
+ @Nullable
+ List<ClientTransactionItem> getCallbacks() {
+ return mActivityCallbacks;
+ }
+
+ /** Get the target activity. */
+ @Nullable
+ public IBinder getActivityToken() {
+ return mActivityToken;
+ }
+
+ /** Get the target state lifecycle request. */
+ ActivityLifecycleItem getLifecycleStateRequest() {
+ return mLifecycleStateRequest;
+ }
+
+ /**
+ * Set the lifecycle state in which the client should be after executing the transaction.
+ * @param stateRequest A lifecycle request initialized with right parameters.
+ */
+ public void setLifecycleStateRequest(ActivityLifecycleItem stateRequest) {
+ mLifecycleStateRequest = stateRequest;
+ }
+
+ /**
+ * Do what needs to be done while the transaction is being scheduled on the client side.
+ * @param clientTransactionHandler Handler on the client side that will executed all operations
+ * requested by transaction items.
+ */
+ public void preExecute(android.app.ClientTransactionHandler clientTransactionHandler) {
+ if (mActivityCallbacks != null) {
+ final int size = mActivityCallbacks.size();
+ for (int i = 0; i < size; ++i) {
+ mActivityCallbacks.get(i).preExecute(clientTransactionHandler, mActivityToken);
+ }
+ }
+ if (mLifecycleStateRequest != null) {
+ mLifecycleStateRequest.preExecute(clientTransactionHandler, mActivityToken);
+ }
+ }
+
+ /**
+ * Schedule the transaction after it was initialized. It will be send to client and all its
+ * individual parts will be applied in the following sequence:
+ * 1. The client calls {@link #preExecute(ClientTransactionHandler)}, which triggers all work
+ * that needs to be done before actually scheduling the transaction for callbacks and
+ * lifecycle state request.
+ * 2. The transaction message is scheduled.
+ * 3. The client calls {@link TransactionExecutor#execute(ClientTransaction)}, which executes
+ * all callbacks and necessary lifecycle transitions.
+ */
+ public void schedule() throws RemoteException {
+ mClient.scheduleTransaction(this);
+ }
+
+
+ // ObjectPoolItem implementation
+
+ private ClientTransaction() {}
+
+ /** Obtain an instance initialized with provided params. */
+ public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
+ ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
+ if (instance == null) {
+ instance = new ClientTransaction();
+ }
+ instance.mClient = client;
+ instance.mActivityToken = activityToken;
+
+ return instance;
+ }
+
+ @Override
+ public void recycle() {
+ if (mActivityCallbacks != null) {
+ int size = mActivityCallbacks.size();
+ for (int i = 0; i < size; i++) {
+ mActivityCallbacks.get(i).recycle();
+ }
+ mActivityCallbacks.clear();
+ }
+ if (mLifecycleStateRequest != null) {
+ mLifecycleStateRequest.recycle();
+ mLifecycleStateRequest = null;
+ }
+ mClient = null;
+ mActivityToken = null;
+ ObjectPool.recycle(this);
+ }
+
+
+ // Parcelable implementation
+
+ /** Write to Parcel. */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongBinder(mClient.asBinder());
+ final boolean writeActivityToken = mActivityToken != null;
+ dest.writeBoolean(writeActivityToken);
+ if (writeActivityToken) {
+ dest.writeStrongBinder(mActivityToken);
+ }
+ dest.writeParcelable(mLifecycleStateRequest, flags);
+ final boolean writeActivityCallbacks = mActivityCallbacks != null;
+ dest.writeBoolean(writeActivityCallbacks);
+ if (writeActivityCallbacks) {
+ dest.writeParcelableList(mActivityCallbacks, flags);
+ }
+ }
+
+ /** Read from Parcel. */
+ private ClientTransaction(Parcel in) {
+ mClient = (IApplicationThread) in.readStrongBinder();
+ final boolean readActivityToken = in.readBoolean();
+ if (readActivityToken) {
+ mActivityToken = in.readStrongBinder();
+ }
+ mLifecycleStateRequest = in.readParcelable(getClass().getClassLoader());
+ final boolean readActivityCallbacks = in.readBoolean();
+ if (readActivityCallbacks) {
+ mActivityCallbacks = new ArrayList<>();
+ in.readParcelableList(mActivityCallbacks, getClass().getClassLoader());
+ }
+ }
+
+ public static final Creator<ClientTransaction> CREATOR =
+ new Creator<ClientTransaction>() {
+ public ClientTransaction createFromParcel(Parcel in) {
+ return new ClientTransaction(in);
+ }
+
+ public ClientTransaction[] newArray(int size) {
+ return new ClientTransaction[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final ClientTransaction other = (ClientTransaction) o;
+ return Objects.equals(mActivityCallbacks, other.mActivityCallbacks)
+ && Objects.equals(mLifecycleStateRequest, other.mLifecycleStateRequest)
+ && mClient == other.mClient
+ && mActivityToken == other.mActivityToken;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + Objects.hashCode(mActivityCallbacks);
+ result = 31 * result + Objects.hashCode(mLifecycleStateRequest);
+ return result;
+ }
+}
diff --git a/core/java/android/app/servertransaction/ClientTransactionItem.java b/core/java/android/app/servertransaction/ClientTransactionItem.java
new file mode 100644
index 0000000..6f2cc00
--- /dev/null
+++ b/core/java/android/app/servertransaction/ClientTransactionItem.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import static android.app.servertransaction.ActivityLifecycleItem.LifecycleState;
+import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED;
+
+import android.os.Parcelable;
+
+/**
+ * A callback message to a client that can be scheduled and executed.
+ * Examples of these might be activity configuration change, multi-window mode change, activity
+ * result delivery etc.
+ *
+ * @see ClientTransaction
+ * @see com.android.server.am.ClientLifecycleManager
+ * @hide
+ */
+public abstract class ClientTransactionItem implements BaseClientRequest, Parcelable {
+
+ /** Get the state in which this callback can be executed. */
+ @LifecycleState
+ public int getPreExecutionState() {
+ return UNDEFINED;
+ }
+
+ /** Get the state that must follow this callback. */
+ @LifecycleState
+ public int getPostExecutionState() {
+ return UNDEFINED;
+ }
+
+
+ // Parcelable
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/app/servertransaction/ConfigurationChangeItem.java b/core/java/android/app/servertransaction/ConfigurationChangeItem.java
new file mode 100644
index 0000000..4ab7251
--- /dev/null
+++ b/core/java/android/app/servertransaction/ConfigurationChangeItem.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import android.app.ClientTransactionHandler;
+import android.content.res.Configuration;
+import android.os.IBinder;
+import android.os.Parcel;
+
+import java.util.Objects;
+
+/**
+ * App configuration change message.
+ * @hide
+ */
+public class ConfigurationChangeItem extends ClientTransactionItem {
+
+ private Configuration mConfiguration;
+
+ @Override
+ public void preExecute(android.app.ClientTransactionHandler client, IBinder token) {
+ client.updatePendingConfiguration(mConfiguration);
+ }
+
+ @Override
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ client.handleConfigurationChanged(mConfiguration);
+ }
+
+
+ // ObjectPoolItem implementation
+
+ private ConfigurationChangeItem() {}
+
+ /** Obtain an instance initialized with provided params. */
+ public static ConfigurationChangeItem obtain(Configuration config) {
+ ConfigurationChangeItem instance = ObjectPool.obtain(ConfigurationChangeItem.class);
+ if (instance == null) {
+ instance = new ConfigurationChangeItem();
+ }
+ instance.mConfiguration = config;
+
+ return instance;
+ }
+
+ @Override
+ public void recycle() {
+ mConfiguration = null;
+ ObjectPool.recycle(this);
+ }
+
+
+ // Parcelable implementation
+
+ /** Write to Parcel. */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeTypedObject(mConfiguration, flags);
+ }
+
+ /** Read from Parcel. */
+ private ConfigurationChangeItem(Parcel in) {
+ mConfiguration = in.readTypedObject(Configuration.CREATOR);
+ }
+
+ public static final Creator<ConfigurationChangeItem> CREATOR =
+ new Creator<ConfigurationChangeItem>() {
+ public ConfigurationChangeItem createFromParcel(Parcel in) {
+ return new ConfigurationChangeItem(in);
+ }
+
+ public ConfigurationChangeItem[] newArray(int size) {
+ return new ConfigurationChangeItem[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final ConfigurationChangeItem other = (ConfigurationChangeItem) o;
+ return Objects.equals(mConfiguration, other.mConfiguration);
+ }
+
+ @Override
+ public int hashCode() {
+ return mConfiguration.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "ConfigurationChangeItem{config=" + mConfiguration + "}";
+ }
+}
diff --git a/core/java/android/app/servertransaction/DestroyActivityItem.java b/core/java/android/app/servertransaction/DestroyActivityItem.java
new file mode 100644
index 0000000..83da5f3
--- /dev/null
+++ b/core/java/android/app/servertransaction/DestroyActivityItem.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+
+import android.app.ClientTransactionHandler;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Trace;
+
+/**
+ * Request to destroy an activity.
+ * @hide
+ */
+public class DestroyActivityItem extends ActivityLifecycleItem {
+
+ private boolean mFinished;
+ private int mConfigChanges;
+
+ @Override
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy");
+ client.handleDestroyActivity(token, mFinished, mConfigChanges,
+ false /* getNonConfigInstance */);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+ }
+
+ @Override
+ public int getTargetState() {
+ return ON_DESTROY;
+ }
+
+
+ // ObjectPoolItem implementation
+
+ private DestroyActivityItem() {}
+
+ /** Obtain an instance initialized with provided params. */
+ public static DestroyActivityItem obtain(boolean finished, int configChanges) {
+ DestroyActivityItem instance = ObjectPool.obtain(DestroyActivityItem.class);
+ if (instance == null) {
+ instance = new DestroyActivityItem();
+ }
+ instance.mFinished = finished;
+ instance.mConfigChanges = configChanges;
+
+ return instance;
+ }
+
+ @Override
+ public void recycle() {
+ mFinished = false;
+ mConfigChanges = 0;
+ ObjectPool.recycle(this);
+ }
+
+
+ // Parcelable implementation
+
+ /** Write to Parcel. */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBoolean(mFinished);
+ dest.writeInt(mConfigChanges);
+ }
+
+ /** Read from Parcel. */
+ private DestroyActivityItem(Parcel in) {
+ mFinished = in.readBoolean();
+ mConfigChanges = in.readInt();
+ }
+
+ public static final Creator<DestroyActivityItem> CREATOR =
+ new Creator<DestroyActivityItem>() {
+ public DestroyActivityItem createFromParcel(Parcel in) {
+ return new DestroyActivityItem(in);
+ }
+
+ public DestroyActivityItem[] newArray(int size) {
+ return new DestroyActivityItem[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final DestroyActivityItem other = (DestroyActivityItem) o;
+ return mFinished == other.mFinished && mConfigChanges == other.mConfigChanges;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + (mFinished ? 1 : 0);
+ result = 31 * result + mConfigChanges;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "DestroyActivityItem{finished=" + mFinished + ",mConfigChanges="
+ + mConfigChanges + "}";
+ }
+}
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
new file mode 100644
index 0000000..7be82bf
--- /dev/null
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+
+import android.app.ActivityThread.ActivityClientRecord;
+import android.app.ClientTransactionHandler;
+import android.app.ProfilerInfo;
+import android.app.ResultInfo;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
+import android.os.BaseBundle;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.PersistableBundle;
+import android.os.Trace;
+
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.content.ReferrerIntent;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Request to launch an activity.
+ * @hide
+ */
+public class LaunchActivityItem extends ClientTransactionItem {
+
+ private Intent mIntent;
+ private int mIdent;
+ private ActivityInfo mInfo;
+ private Configuration mCurConfig;
+ private Configuration mOverrideConfig;
+ private CompatibilityInfo mCompatInfo;
+ private String mReferrer;
+ private IVoiceInteractor mVoiceInteractor;
+ private int mProcState;
+ private Bundle mState;
+ private PersistableBundle mPersistentState;
+ private List<ResultInfo> mPendingResults;
+ private List<ReferrerIntent> mPendingNewIntents;
+ private boolean mIsForward;
+ private ProfilerInfo mProfilerInfo;
+
+ @Override
+ public void preExecute(ClientTransactionHandler client, IBinder token) {
+ client.updateProcessState(mProcState, false);
+ client.updatePendingConfiguration(mCurConfig);
+ }
+
+ @Override
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
+ ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
+ mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
+ mPendingResults, mPendingNewIntents, mIsForward,
+ mProfilerInfo, client);
+ client.handleLaunchActivity(r, pendingActions);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+ }
+
+
+ // ObjectPoolItem implementation
+
+ private LaunchActivityItem() {}
+
+ /** Obtain an instance initialized with provided params. */
+ public static LaunchActivityItem obtain(Intent intent, int ident, ActivityInfo info,
+ Configuration curConfig, Configuration overrideConfig, CompatibilityInfo compatInfo,
+ String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
+ PersistableBundle persistentState, List<ResultInfo> pendingResults,
+ List<ReferrerIntent> pendingNewIntents, boolean isForward, ProfilerInfo profilerInfo) {
+ LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class);
+ if (instance == null) {
+ instance = new LaunchActivityItem();
+ }
+ setValues(instance, intent, ident, info, curConfig, overrideConfig, compatInfo, referrer,
+ voiceInteractor, procState, state, persistentState, pendingResults,
+ pendingNewIntents, isForward, profilerInfo);
+
+ return instance;
+ }
+
+ @Override
+ public void recycle() {
+ setValues(this, null, 0, null, null, null, null, null, null, 0, null, null, null, null,
+ false, null);
+ ObjectPool.recycle(this);
+ }
+
+
+ // Parcelable implementation
+
+ /** Write from Parcel. */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeTypedObject(mIntent, flags);
+ dest.writeInt(mIdent);
+ dest.writeTypedObject(mInfo, flags);
+ dest.writeTypedObject(mCurConfig, flags);
+ dest.writeTypedObject(mOverrideConfig, flags);
+ dest.writeTypedObject(mCompatInfo, flags);
+ dest.writeString(mReferrer);
+ dest.writeStrongInterface(mVoiceInteractor);
+ dest.writeInt(mProcState);
+ dest.writeBundle(mState);
+ dest.writePersistableBundle(mPersistentState);
+ dest.writeTypedList(mPendingResults, flags);
+ dest.writeTypedList(mPendingNewIntents, flags);
+ dest.writeBoolean(mIsForward);
+ dest.writeTypedObject(mProfilerInfo, flags);
+ }
+
+ /** Read from Parcel. */
+ private LaunchActivityItem(Parcel in) {
+ setValues(this, in.readTypedObject(Intent.CREATOR), in.readInt(),
+ in.readTypedObject(ActivityInfo.CREATOR), in.readTypedObject(Configuration.CREATOR),
+ in.readTypedObject(Configuration.CREATOR),
+ in.readTypedObject(CompatibilityInfo.CREATOR), in.readString(),
+ IVoiceInteractor.Stub.asInterface(in.readStrongBinder()), in.readInt(),
+ in.readBundle(getClass().getClassLoader()),
+ in.readPersistableBundle(getClass().getClassLoader()),
+ in.createTypedArrayList(ResultInfo.CREATOR),
+ in.createTypedArrayList(ReferrerIntent.CREATOR), in.readBoolean(),
+ in.readTypedObject(ProfilerInfo.CREATOR));
+ }
+
+ public static final Creator<LaunchActivityItem> CREATOR =
+ new Creator<LaunchActivityItem>() {
+ public LaunchActivityItem createFromParcel(Parcel in) {
+ return new LaunchActivityItem(in);
+ }
+
+ public LaunchActivityItem[] newArray(int size) {
+ return new LaunchActivityItem[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final LaunchActivityItem other = (LaunchActivityItem) o;
+ final boolean intentsEqual = (mIntent == null && other.mIntent == null)
+ || (mIntent != null && mIntent.filterEquals(other.mIntent));
+ return intentsEqual && mIdent == other.mIdent
+ && activityInfoEqual(other.mInfo) && Objects.equals(mCurConfig, other.mCurConfig)
+ && Objects.equals(mOverrideConfig, other.mOverrideConfig)
+ && Objects.equals(mCompatInfo, other.mCompatInfo)
+ && Objects.equals(mReferrer, other.mReferrer)
+ && mProcState == other.mProcState && areBundlesEqual(mState, other.mState)
+ && areBundlesEqual(mPersistentState, other.mPersistentState)
+ && Objects.equals(mPendingResults, other.mPendingResults)
+ && Objects.equals(mPendingNewIntents, other.mPendingNewIntents)
+ && mIsForward == other.mIsForward
+ && Objects.equals(mProfilerInfo, other.mProfilerInfo);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + mIntent.filterHashCode();
+ result = 31 * result + mIdent;
+ result = 31 * result + Objects.hashCode(mCurConfig);
+ result = 31 * result + Objects.hashCode(mOverrideConfig);
+ result = 31 * result + Objects.hashCode(mCompatInfo);
+ result = 31 * result + Objects.hashCode(mReferrer);
+ result = 31 * result + Objects.hashCode(mProcState);
+ result = 31 * result + (mState != null ? mState.size() : 0);
+ result = 31 * result + (mPersistentState != null ? mPersistentState.size() : 0);
+ result = 31 * result + Objects.hashCode(mPendingResults);
+ result = 31 * result + Objects.hashCode(mPendingNewIntents);
+ result = 31 * result + (mIsForward ? 1 : 0);
+ result = 31 * result + Objects.hashCode(mProfilerInfo);
+ return result;
+ }
+
+ private boolean activityInfoEqual(ActivityInfo other) {
+ if (mInfo == null) {
+ return other == null;
+ }
+ return other != null && mInfo.flags == other.flags
+ && mInfo.maxAspectRatio == other.maxAspectRatio
+ && Objects.equals(mInfo.launchToken, other.launchToken)
+ && Objects.equals(mInfo.getComponentName(), other.getComponentName());
+ }
+
+ private static boolean areBundlesEqual(BaseBundle extras, BaseBundle newExtras) {
+ if (extras == null || newExtras == null) {
+ return extras == newExtras;
+ }
+
+ if (extras.size() != newExtras.size()) {
+ return false;
+ }
+
+ for (String key : extras.keySet()) {
+ if (key != null) {
+ final Object value = extras.get(key);
+ final Object newValue = newExtras.get(key);
+ if (!Objects.equals(value, newValue)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "LaunchActivityItem{intent=" + mIntent + ",ident=" + mIdent + ",info=" + mInfo
+ + ",curConfig=" + mCurConfig + ",overrideConfig=" + mOverrideConfig
+ + ",referrer=" + mReferrer + ",procState=" + mProcState + ",state=" + mState
+ + ",persistentState=" + mPersistentState + ",pendingResults=" + mPendingResults
+ + ",pendingNewIntents=" + mPendingNewIntents + ",profilerInfo=" + mProfilerInfo
+ + "}";
+ }
+
+ // Using the same method to set and clear values to make sure we don't forget anything
+ private static void setValues(LaunchActivityItem instance, Intent intent, int ident,
+ ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
+ CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
+ int procState, Bundle state, PersistableBundle persistentState,
+ List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
+ boolean isForward, ProfilerInfo profilerInfo) {
+ instance.mIntent = intent;
+ instance.mIdent = ident;
+ instance.mInfo = info;
+ instance.mCurConfig = curConfig;
+ instance.mOverrideConfig = overrideConfig;
+ instance.mCompatInfo = compatInfo;
+ instance.mReferrer = referrer;
+ instance.mVoiceInteractor = voiceInteractor;
+ instance.mProcState = procState;
+ instance.mState = state;
+ instance.mPersistentState = persistentState;
+ instance.mPendingResults = pendingResults;
+ instance.mPendingNewIntents = pendingNewIntents;
+ instance.mIsForward = isForward;
+ instance.mProfilerInfo = profilerInfo;
+ }
+}
diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java
new file mode 100644
index 0000000..b3dddfb3
--- /dev/null
+++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+
+import android.app.ClientTransactionHandler;
+import android.content.res.Configuration;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Trace;
+
+import java.util.Objects;
+
+/**
+ * Activity move to a different display message.
+ * @hide
+ */
+public class MoveToDisplayItem extends ClientTransactionItem {
+
+ private int mTargetDisplayId;
+ private Configuration mConfiguration;
+
+ @Override
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityMovedToDisplay");
+ client.handleActivityConfigurationChanged(token, mConfiguration, mTargetDisplayId);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+ }
+
+
+ // ObjectPoolItem implementation
+
+ private MoveToDisplayItem() {}
+
+ /** Obtain an instance initialized with provided params. */
+ public static MoveToDisplayItem obtain(int targetDisplayId, Configuration configuration) {
+ MoveToDisplayItem instance = ObjectPool.obtain(MoveToDisplayItem.class);
+ if (instance == null) {
+ instance = new MoveToDisplayItem();
+ }
+ instance.mTargetDisplayId = targetDisplayId;
+ instance.mConfiguration = configuration;
+
+ return instance;
+ }
+
+ @Override
+ public void recycle() {
+ mTargetDisplayId = 0;
+ mConfiguration = null;
+ ObjectPool.recycle(this);
+ }
+
+
+ // Parcelable implementation
+
+ /** Write to Parcel. */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mTargetDisplayId);
+ dest.writeTypedObject(mConfiguration, flags);
+ }
+
+ /** Read from Parcel. */
+ private MoveToDisplayItem(Parcel in) {
+ mTargetDisplayId = in.readInt();
+ mConfiguration = in.readTypedObject(Configuration.CREATOR);
+ }
+
+ public static final Creator<MoveToDisplayItem> CREATOR = new Creator<MoveToDisplayItem>() {
+ public MoveToDisplayItem createFromParcel(Parcel in) {
+ return new MoveToDisplayItem(in);
+ }
+
+ public MoveToDisplayItem[] newArray(int size) {
+ return new MoveToDisplayItem[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final MoveToDisplayItem other = (MoveToDisplayItem) o;
+ return mTargetDisplayId == other.mTargetDisplayId
+ && Objects.equals(mConfiguration, other.mConfiguration);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + mTargetDisplayId;
+ result = 31 * result + mConfiguration.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "MoveToDisplayItem{targetDisplayId=" + mTargetDisplayId
+ + ",configuration=" + mConfiguration + "}";
+ }
+}
diff --git a/core/java/android/app/servertransaction/MultiWindowModeChangeItem.java b/core/java/android/app/servertransaction/MultiWindowModeChangeItem.java
new file mode 100644
index 0000000..c3022d6
--- /dev/null
+++ b/core/java/android/app/servertransaction/MultiWindowModeChangeItem.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import android.app.ClientTransactionHandler;
+import android.content.res.Configuration;
+import android.os.IBinder;
+import android.os.Parcel;
+
+import java.util.Objects;
+
+/**
+ * Multi-window mode change message.
+ * @hide
+ */
+// TODO(lifecycler): Remove the use of this and just use the configuration change message to
+// communicate multi-window mode change with WindowConfiguration.
+public class MultiWindowModeChangeItem extends ClientTransactionItem {
+
+ private boolean mIsInMultiWindowMode;
+ private Configuration mOverrideConfig;
+
+ @Override
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ client.handleMultiWindowModeChanged(token, mIsInMultiWindowMode, mOverrideConfig);
+ }
+
+
+ // ObjectPoolItem implementation
+
+ private MultiWindowModeChangeItem() {}
+
+ /** Obtain an instance initialized with provided params. */
+ public static MultiWindowModeChangeItem obtain(boolean isInMultiWindowMode,
+ Configuration overrideConfig) {
+ MultiWindowModeChangeItem instance = ObjectPool.obtain(MultiWindowModeChangeItem.class);
+ if (instance == null) {
+ instance = new MultiWindowModeChangeItem();
+ }
+ instance.mIsInMultiWindowMode = isInMultiWindowMode;
+ instance.mOverrideConfig = overrideConfig;
+
+ return instance;
+ }
+
+ @Override
+ public void recycle() {
+ mIsInMultiWindowMode = false;
+ mOverrideConfig = null;
+ ObjectPool.recycle(this);
+ }
+
+
+ // Parcelable implementation
+
+ /** Write to Parcel. */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBoolean(mIsInMultiWindowMode);
+ dest.writeTypedObject(mOverrideConfig, flags);
+ }
+
+ /** Read from Parcel. */
+ private MultiWindowModeChangeItem(Parcel in) {
+ mIsInMultiWindowMode = in.readBoolean();
+ mOverrideConfig = in.readTypedObject(Configuration.CREATOR);
+ }
+
+ public static final Creator<MultiWindowModeChangeItem> CREATOR =
+ new Creator<MultiWindowModeChangeItem>() {
+ public MultiWindowModeChangeItem createFromParcel(Parcel in) {
+ return new MultiWindowModeChangeItem(in);
+ }
+
+ public MultiWindowModeChangeItem[] newArray(int size) {
+ return new MultiWindowModeChangeItem[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final MultiWindowModeChangeItem other = (MultiWindowModeChangeItem) o;
+ return mIsInMultiWindowMode == other.mIsInMultiWindowMode
+ && Objects.equals(mOverrideConfig, other.mOverrideConfig);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + (mIsInMultiWindowMode ? 1 : 0);
+ result = 31 * result + mOverrideConfig.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "MultiWindowModeChangeItem{isInMultiWindowMode=" + mIsInMultiWindowMode
+ + ",overrideConfig=" + mOverrideConfig + "}";
+ }
+}
diff --git a/core/java/android/app/servertransaction/NewIntentItem.java b/core/java/android/app/servertransaction/NewIntentItem.java
new file mode 100644
index 0000000..7dfde73
--- /dev/null
+++ b/core/java/android/app/servertransaction/NewIntentItem.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import android.app.ClientTransactionHandler;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.Trace;
+
+import com.android.internal.content.ReferrerIntent;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * New intent message.
+ * @hide
+ */
+public class NewIntentItem extends ClientTransactionItem {
+
+ private List<ReferrerIntent> mIntents;
+ private boolean mPause;
+
+ // TODO(lifecycler): Switch new intent handling to this scheme.
+ /*@Override
+ public int getPreExecutionState() {
+ return ON_PAUSE;
+ }
+
+ @Override
+ public int getPostExecutionState() {
+ return ON_RESUME;
+ }*/
+
+ @Override
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityNewIntent");
+ client.handleNewIntent(token, mIntents, mPause);
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
+
+
+ // ObjectPoolItem implementation
+
+ private NewIntentItem() {}
+
+ /** Obtain an instance initialized with provided params. */
+ public static NewIntentItem obtain(List<ReferrerIntent> intents, boolean pause) {
+ NewIntentItem instance = ObjectPool.obtain(NewIntentItem.class);
+ if (instance == null) {
+ instance = new NewIntentItem();
+ }
+ instance.mIntents = intents;
+ instance.mPause = pause;
+
+ return instance;
+ }
+
+ @Override
+ public void recycle() {
+ mIntents = null;
+ mPause = false;
+ ObjectPool.recycle(this);
+ }
+
+
+ // Parcelable implementation
+
+ /** Write to Parcel. */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBoolean(mPause);
+ dest.writeTypedList(mIntents, flags);
+ }
+
+ /** Read from Parcel. */
+ private NewIntentItem(Parcel in) {
+ mPause = in.readBoolean();
+ mIntents = in.createTypedArrayList(ReferrerIntent.CREATOR);
+ }
+
+ public static final Parcelable.Creator<NewIntentItem> CREATOR =
+ new Parcelable.Creator<NewIntentItem>() {
+ public NewIntentItem createFromParcel(Parcel in) {
+ return new NewIntentItem(in);
+ }
+
+ public NewIntentItem[] newArray(int size) {
+ return new NewIntentItem[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final NewIntentItem other = (NewIntentItem) o;
+ return mPause == other.mPause && Objects.equals(mIntents, other.mIntents);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + (mPause ? 1 : 0);
+ result = 31 * result + mIntents.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "NewIntentItem{pause=" + mPause + ",intents=" + mIntents + "}";
+ }
+}
diff --git a/core/java/android/app/servertransaction/ObjectPool.java b/core/java/android/app/servertransaction/ObjectPool.java
new file mode 100644
index 0000000..9812125
--- /dev/null
+++ b/core/java/android/app/servertransaction/ObjectPool.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+/**
+ * An object pool that can provide reused objects if available.
+ * @hide
+ */
+class ObjectPool {
+
+ private static final Object sPoolSync = new Object();
+ private static final Map<Class, LinkedList<? extends ObjectPoolItem>> sPoolMap =
+ new HashMap<>();
+
+ private static final int MAX_POOL_SIZE = 50;
+
+ /**
+ * Obtain an instance of a specific class from the pool
+ * @param itemClass The class of the object we're looking for.
+ * @return An instance or null if there is none.
+ */
+ public static <T extends ObjectPoolItem> T obtain(Class<T> itemClass) {
+ synchronized (sPoolSync) {
+ @SuppressWarnings("unchecked")
+ LinkedList<T> itemPool = (LinkedList<T>) sPoolMap.get(itemClass);
+ if (itemPool != null && !itemPool.isEmpty()) {
+ return itemPool.poll();
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Recycle the object to the pool. The object should be properly cleared before this.
+ * @param item The object to recycle.
+ * @see ObjectPoolItem#recycle()
+ */
+ public static <T extends ObjectPoolItem> void recycle(T item) {
+ synchronized (sPoolSync) {
+ @SuppressWarnings("unchecked")
+ LinkedList<T> itemPool = (LinkedList<T>) sPoolMap.get(item.getClass());
+ if (itemPool == null) {
+ itemPool = new LinkedList<>();
+ sPoolMap.put(item.getClass(), itemPool);
+ }
+ if (itemPool.contains(item)) {
+ throw new IllegalStateException("Trying to recycle already recycled item");
+ }
+
+ if (itemPool.size() < MAX_POOL_SIZE) {
+ itemPool.add(item);
+ }
+ }
+ }
+}
diff --git a/core/java/android/app/servertransaction/ObjectPoolItem.java b/core/java/android/app/servertransaction/ObjectPoolItem.java
new file mode 100644
index 0000000..17bd4f3
--- /dev/null
+++ b/core/java/android/app/servertransaction/ObjectPoolItem.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+/**
+ * Base interface for all lifecycle items that can be put in object pool.
+ * @hide
+ */
+public interface ObjectPoolItem {
+ /**
+ * Clear the contents of the item and putting it to a pool. The implementation should call
+ * {@link ObjectPool#recycle(ObjectPoolItem)} passing itself.
+ */
+ void recycle();
+}
diff --git a/core/java/android/app/servertransaction/PauseActivityItem.java b/core/java/android/app/servertransaction/PauseActivityItem.java
new file mode 100644
index 0000000..880fef7
--- /dev/null
+++ b/core/java/android/app/servertransaction/PauseActivityItem.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+
+import android.app.ActivityManager;
+import android.app.ClientTransactionHandler;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.Trace;
+
+/**
+ * Request to move an activity to paused state.
+ * @hide
+ */
+public class PauseActivityItem extends ActivityLifecycleItem {
+
+ private static final String TAG = "PauseActivityItem";
+
+ private boolean mFinished;
+ private boolean mUserLeaving;
+ private int mConfigChanges;
+ private boolean mDontReport;
+
+ @Override
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
+ client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, mDontReport,
+ pendingActions);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+ }
+
+ @Override
+ public int getTargetState() {
+ return ON_PAUSE;
+ }
+
+ @Override
+ public void postExecute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ if (mDontReport) {
+ return;
+ }
+ try {
+ // TODO(lifecycler): Use interface callback instead of AMS.
+ ActivityManager.getService().activityPaused(token);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+
+ // ObjectPoolItem implementation
+
+ private PauseActivityItem() {}
+
+ /** Obtain an instance initialized with provided params. */
+ public static PauseActivityItem obtain(boolean finished, boolean userLeaving, int configChanges,
+ boolean dontReport) {
+ PauseActivityItem instance = ObjectPool.obtain(PauseActivityItem.class);
+ if (instance == null) {
+ instance = new PauseActivityItem();
+ }
+ instance.mFinished = finished;
+ instance.mUserLeaving = userLeaving;
+ instance.mConfigChanges = configChanges;
+ instance.mDontReport = dontReport;
+
+ return instance;
+ }
+
+ /** Obtain an instance initialized with default params. */
+ public static PauseActivityItem obtain() {
+ PauseActivityItem instance = ObjectPool.obtain(PauseActivityItem.class);
+ if (instance == null) {
+ instance = new PauseActivityItem();
+ }
+ instance.mFinished = false;
+ instance.mUserLeaving = false;
+ instance.mConfigChanges = 0;
+ instance.mDontReport = true;
+
+ return instance;
+ }
+
+ @Override
+ public void recycle() {
+ mFinished = false;
+ mUserLeaving = false;
+ mConfigChanges = 0;
+ mDontReport = false;
+ ObjectPool.recycle(this);
+ }
+
+ // Parcelable implementation
+
+ /** Write to Parcel. */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBoolean(mFinished);
+ dest.writeBoolean(mUserLeaving);
+ dest.writeInt(mConfigChanges);
+ dest.writeBoolean(mDontReport);
+ }
+
+ /** Read from Parcel. */
+ private PauseActivityItem(Parcel in) {
+ mFinished = in.readBoolean();
+ mUserLeaving = in.readBoolean();
+ mConfigChanges = in.readInt();
+ mDontReport = in.readBoolean();
+ }
+
+ public static final Creator<PauseActivityItem> CREATOR =
+ new Creator<PauseActivityItem>() {
+ public PauseActivityItem createFromParcel(Parcel in) {
+ return new PauseActivityItem(in);
+ }
+
+ public PauseActivityItem[] newArray(int size) {
+ return new PauseActivityItem[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final PauseActivityItem other = (PauseActivityItem) o;
+ return mFinished == other.mFinished && mUserLeaving == other.mUserLeaving
+ && mConfigChanges == other.mConfigChanges && mDontReport == other.mDontReport;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + (mFinished ? 1 : 0);
+ result = 31 * result + (mUserLeaving ? 1 : 0);
+ result = 31 * result + mConfigChanges;
+ result = 31 * result + (mDontReport ? 1 : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "PauseActivityItem{finished=" + mFinished + ",userLeaving=" + mUserLeaving
+ + ",configChanges=" + mConfigChanges + ",dontReport=" + mDontReport + "}";
+ }
+}
diff --git a/core/java/android/app/servertransaction/PendingTransactionActions.java b/core/java/android/app/servertransaction/PendingTransactionActions.java
new file mode 100644
index 0000000..073d28c
--- /dev/null
+++ b/core/java/android/app/servertransaction/PendingTransactionActions.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import static android.app.ActivityThread.DEBUG_MEMORY_TRIM;
+
+import android.app.ActivityManager;
+import android.app.ActivityThread.ActivityClientRecord;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+import android.os.RemoteException;
+import android.os.TransactionTooLargeException;
+import android.util.Log;
+import android.util.LogWriter;
+import android.util.Slog;
+
+import com.android.internal.util.IndentingPrintWriter;
+
+/**
+ * Container that has data pending to be used at later stages of
+ * {@link android.app.servertransaction.ClientTransaction}.
+ * An instance of this class is passed to each individual transaction item, so it can use some
+ * information from previous steps or add some for the following steps.
+ *
+ * @hide
+ */
+public class PendingTransactionActions {
+ private boolean mRestoreInstanceState;
+ private boolean mCallOnPostCreate;
+ private Bundle mOldState;
+ private StopInfo mStopInfo;
+
+ public PendingTransactionActions() {
+ clear();
+ }
+
+ /** Reset the state of the instance to default, non-initialized values. */
+ public void clear() {
+ mRestoreInstanceState = false;
+ mCallOnPostCreate = false;
+ mOldState = null;
+ mStopInfo = null;
+ }
+
+ /** Getter */
+ public boolean shouldRestoreInstanceState() {
+ return mRestoreInstanceState;
+ }
+
+ public void setRestoreInstanceState(boolean restoreInstanceState) {
+ mRestoreInstanceState = restoreInstanceState;
+ }
+
+ /** Getter */
+ public boolean shouldCallOnPostCreate() {
+ return mCallOnPostCreate;
+ }
+
+ public void setCallOnPostCreate(boolean callOnPostCreate) {
+ mCallOnPostCreate = callOnPostCreate;
+ }
+
+ public Bundle getOldState() {
+ return mOldState;
+ }
+
+ public void setOldState(Bundle oldState) {
+ mOldState = oldState;
+ }
+
+ public StopInfo getStopInfo() {
+ return mStopInfo;
+ }
+
+ public void setStopInfo(StopInfo stopInfo) {
+ mStopInfo = stopInfo;
+ }
+
+ /** Reports to server about activity stop. */
+ public static class StopInfo implements Runnable {
+ private static final String TAG = "ActivityStopInfo";
+
+ private ActivityClientRecord mActivity;
+ private Bundle mState;
+ private PersistableBundle mPersistentState;
+ private CharSequence mDescription;
+
+ public void setActivity(ActivityClientRecord activity) {
+ mActivity = activity;
+ }
+
+ public void setState(Bundle state) {
+ mState = state;
+ }
+
+ public void setPersistentState(PersistableBundle persistentState) {
+ mPersistentState = persistentState;
+ }
+
+ public void setDescription(CharSequence description) {
+ mDescription = description;
+ }
+
+ @Override
+ public void run() {
+ // Tell activity manager we have been stopped.
+ try {
+ if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + mActivity);
+ // TODO(lifecycler): Use interface callback instead of AMS.
+ ActivityManager.getService().activityStopped(
+ mActivity.token, mState, mPersistentState, mDescription);
+ } catch (RemoteException ex) {
+ // Dump statistics about bundle to help developers debug
+ final LogWriter writer = new LogWriter(Log.WARN, TAG);
+ final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
+ pw.println("Bundle stats:");
+ Bundle.dumpStats(pw, mState);
+ pw.println("PersistableBundle stats:");
+ Bundle.dumpStats(pw, mPersistentState);
+
+ if (ex instanceof TransactionTooLargeException
+ && mActivity.packageInfo.getTargetSdkVersion() < Build.VERSION_CODES.N) {
+ Log.e(TAG, "App sent too much data in instance state, so it was ignored", ex);
+ return;
+ }
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+ }
+}
diff --git a/core/java/android/app/servertransaction/PipModeChangeItem.java b/core/java/android/app/servertransaction/PipModeChangeItem.java
new file mode 100644
index 0000000..b999cd7
--- /dev/null
+++ b/core/java/android/app/servertransaction/PipModeChangeItem.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import android.app.ClientTransactionHandler;
+import android.content.res.Configuration;
+import android.os.IBinder;
+import android.os.Parcel;
+
+import java.util.Objects;
+
+/**
+ * Picture in picture mode change message.
+ * @hide
+ */
+// TODO(lifecycler): Remove the use of this and just use the configuration change message to
+// communicate multi-window mode change with WindowConfiguration.
+public class PipModeChangeItem extends ClientTransactionItem {
+
+ private boolean mIsInPipMode;
+ private Configuration mOverrideConfig;
+
+ @Override
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ client.handlePictureInPictureModeChanged(token, mIsInPipMode, mOverrideConfig);
+ }
+
+
+ // ObjectPoolItem implementation
+
+ private PipModeChangeItem() {}
+
+ /** Obtain an instance initialized with provided params. */
+ public static PipModeChangeItem obtain(boolean isInPipMode, Configuration overrideConfig) {
+ PipModeChangeItem instance = ObjectPool.obtain(PipModeChangeItem.class);
+ if (instance == null) {
+ instance = new PipModeChangeItem();
+ }
+ instance.mIsInPipMode = isInPipMode;
+ instance.mOverrideConfig = overrideConfig;
+
+ return instance;
+ }
+
+ @Override
+ public void recycle() {
+ mIsInPipMode = false;
+ mOverrideConfig = null;
+ ObjectPool.recycle(this);
+ }
+
+
+ // Parcelable implementation
+
+ /** Write to Parcel. */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBoolean(mIsInPipMode);
+ dest.writeTypedObject(mOverrideConfig, flags);
+ }
+
+ /** Read from Parcel. */
+ private PipModeChangeItem(Parcel in) {
+ mIsInPipMode = in.readBoolean();
+ mOverrideConfig = in.readTypedObject(Configuration.CREATOR);
+ }
+
+ public static final Creator<PipModeChangeItem> CREATOR =
+ new Creator<PipModeChangeItem>() {
+ public PipModeChangeItem createFromParcel(Parcel in) {
+ return new PipModeChangeItem(in);
+ }
+
+ public PipModeChangeItem[] newArray(int size) {
+ return new PipModeChangeItem[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final PipModeChangeItem other = (PipModeChangeItem) o;
+ return mIsInPipMode == other.mIsInPipMode
+ && Objects.equals(mOverrideConfig, other.mOverrideConfig);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + (mIsInPipMode ? 1 : 0);
+ result = 31 * result + mOverrideConfig.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "PipModeChangeItem{isInPipMode=" + mIsInPipMode
+ + ",overrideConfig=" + mOverrideConfig + "}";
+ }
+}
diff --git a/core/java/android/app/servertransaction/ResumeActivityItem.java b/core/java/android/app/servertransaction/ResumeActivityItem.java
new file mode 100644
index 0000000..9249c6e
--- /dev/null
+++ b/core/java/android/app/servertransaction/ResumeActivityItem.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+
+import android.app.ActivityManager;
+import android.app.ClientTransactionHandler;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.Trace;
+
+/**
+ * Request to move an activity to resumed state.
+ * @hide
+ */
+public class ResumeActivityItem extends ActivityLifecycleItem {
+
+ private static final String TAG = "ResumeActivityItem";
+
+ private int mProcState;
+ private boolean mUpdateProcState;
+ private boolean mIsForward;
+
+ @Override
+ public void preExecute(ClientTransactionHandler client, IBinder token) {
+ if (mUpdateProcState) {
+ client.updateProcessState(mProcState, false);
+ }
+ }
+
+ @Override
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
+ client.handleResumeActivity(token, true /* clearHide */, mIsForward, "RESUME_ACTIVITY");
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+ }
+
+ @Override
+ public void postExecute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ try {
+ // TODO(lifecycler): Use interface callback instead of AMS.
+ ActivityManager.getService().activityResumed(token);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public int getTargetState() {
+ return ON_RESUME;
+ }
+
+
+ // ObjectPoolItem implementation
+
+ private ResumeActivityItem() {}
+
+ /** Obtain an instance initialized with provided params. */
+ public static ResumeActivityItem obtain(int procState, boolean isForward) {
+ ResumeActivityItem instance = ObjectPool.obtain(ResumeActivityItem.class);
+ if (instance == null) {
+ instance = new ResumeActivityItem();
+ }
+ instance.mProcState = procState;
+ instance.mUpdateProcState = true;
+ instance.mIsForward = isForward;
+
+ return instance;
+ }
+
+ /** Obtain an instance initialized with provided params. */
+ public static ResumeActivityItem obtain(boolean isForward) {
+ ResumeActivityItem instance = ObjectPool.obtain(ResumeActivityItem.class);
+ if (instance == null) {
+ instance = new ResumeActivityItem();
+ }
+ instance.mProcState = ActivityManager.PROCESS_STATE_UNKNOWN;
+ instance.mUpdateProcState = false;
+ instance.mIsForward = isForward;
+
+ return instance;
+ }
+
+ @Override
+ public void recycle() {
+ mProcState = ActivityManager.PROCESS_STATE_UNKNOWN;
+ mUpdateProcState = false;
+ mIsForward = false;
+ ObjectPool.recycle(this);
+ }
+
+
+ // Parcelable implementation
+
+ /** Write to Parcel. */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mProcState);
+ dest.writeBoolean(mUpdateProcState);
+ dest.writeBoolean(mIsForward);
+ }
+
+ /** Read from Parcel. */
+ private ResumeActivityItem(Parcel in) {
+ mProcState = in.readInt();
+ mUpdateProcState = in.readBoolean();
+ mIsForward = in.readBoolean();
+ }
+
+ public static final Creator<ResumeActivityItem> CREATOR =
+ new Creator<ResumeActivityItem>() {
+ public ResumeActivityItem createFromParcel(Parcel in) {
+ return new ResumeActivityItem(in);
+ }
+
+ public ResumeActivityItem[] newArray(int size) {
+ return new ResumeActivityItem[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final ResumeActivityItem other = (ResumeActivityItem) o;
+ return mProcState == other.mProcState && mUpdateProcState == other.mUpdateProcState
+ && mIsForward == other.mIsForward;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + mProcState;
+ result = 31 * result + (mUpdateProcState ? 1 : 0);
+ result = 31 * result + (mIsForward ? 1 : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "ResumeActivityItem{procState=" + mProcState
+ + ",updateProcState=" + mUpdateProcState + ",isForward=" + mIsForward + "}";
+ }
+}
diff --git a/core/java/android/app/servertransaction/StopActivityItem.java b/core/java/android/app/servertransaction/StopActivityItem.java
new file mode 100644
index 0000000..5c5c304
--- /dev/null
+++ b/core/java/android/app/servertransaction/StopActivityItem.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+
+import android.app.ClientTransactionHandler;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Trace;
+
+/**
+ * Request to move an activity to stopped state.
+ * @hide
+ */
+public class StopActivityItem extends ActivityLifecycleItem {
+
+ private static final String TAG = "StopActivityItem";
+
+ private boolean mShowWindow;
+ private int mConfigChanges;
+
+ @Override
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
+ client.handleStopActivity(token, mShowWindow, mConfigChanges, pendingActions);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+ }
+
+ @Override
+ public void postExecute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ client.reportStop(pendingActions);
+ }
+
+ @Override
+ public int getTargetState() {
+ return ON_STOP;
+ }
+
+
+ // ObjectPoolItem implementation
+
+ private StopActivityItem() {}
+
+ /** Obtain an instance initialized with provided params. */
+ public static StopActivityItem obtain(boolean showWindow, int configChanges) {
+ StopActivityItem instance = ObjectPool.obtain(StopActivityItem.class);
+ if (instance == null) {
+ instance = new StopActivityItem();
+ }
+ instance.mShowWindow = showWindow;
+ instance.mConfigChanges = configChanges;
+
+ return instance;
+ }
+
+ @Override
+ public void recycle() {
+ mShowWindow = false;
+ mConfigChanges = 0;
+ ObjectPool.recycle(this);
+ }
+
+
+ // Parcelable implementation
+
+ /** Write to Parcel. */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBoolean(mShowWindow);
+ dest.writeInt(mConfigChanges);
+ }
+
+ /** Read from Parcel. */
+ private StopActivityItem(Parcel in) {
+ mShowWindow = in.readBoolean();
+ mConfigChanges = in.readInt();
+ }
+
+ public static final Creator<StopActivityItem> CREATOR =
+ new Creator<StopActivityItem>() {
+ public StopActivityItem createFromParcel(Parcel in) {
+ return new StopActivityItem(in);
+ }
+
+ public StopActivityItem[] newArray(int size) {
+ return new StopActivityItem[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final StopActivityItem other = (StopActivityItem) o;
+ return mShowWindow == other.mShowWindow && mConfigChanges == other.mConfigChanges;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + (mShowWindow ? 1 : 0);
+ result = 31 * result + mConfigChanges;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "StopActivityItem{showWindow=" + mShowWindow + ",configChanges=" + mConfigChanges
+ + "}";
+ }
+}
diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java
new file mode 100644
index 0000000..5b0ea6b
--- /dev/null
+++ b/core/java/android/app/servertransaction/TransactionExecutor.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_DESTROY;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_RESTART;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_START;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
+import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED;
+
+import android.app.ActivityThread.ActivityClientRecord;
+import android.app.ClientTransactionHandler;
+import android.os.IBinder;
+import android.util.IntArray;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.List;
+
+/**
+ * Class that manages transaction execution in the correct order.
+ * @hide
+ */
+public class TransactionExecutor {
+
+ private static final boolean DEBUG_RESOLVER = false;
+ private static final String TAG = "TransactionExecutor";
+
+ private ClientTransactionHandler mTransactionHandler;
+ private PendingTransactionActions mPendingActions = new PendingTransactionActions();
+
+ // Temp holder for lifecycle path.
+ // No direct transition between two states should take more than one complete cycle of 6 states.
+ @ActivityLifecycleItem.LifecycleState
+ private IntArray mLifecycleSequence = new IntArray(6);
+
+ /** Initialize an instance with transaction handler, that will execute all requested actions. */
+ public TransactionExecutor(ClientTransactionHandler clientTransactionHandler) {
+ mTransactionHandler = clientTransactionHandler;
+ }
+
+ /**
+ * Resolve transaction.
+ * First all callbacks will be executed in the order they appear in the list. If a callback
+ * requires a certain pre- or post-execution state, the client will be transitioned accordingly.
+ * Then the client will cycle to the final lifecycle state if provided. Otherwise, it will
+ * either remain in the initial state, or last state needed by a callback.
+ */
+ public void execute(ClientTransaction transaction) {
+ final IBinder token = transaction.getActivityToken();
+ log("Start resolving transaction for client: " + mTransactionHandler + ", token: " + token);
+
+ executeCallbacks(transaction);
+
+ executeLifecycleState(transaction);
+ mPendingActions.clear();
+ log("End resolving transaction");
+ }
+
+ /** Cycle through all states requested by callbacks and execute them at proper times. */
+ @VisibleForTesting
+ public void executeCallbacks(ClientTransaction transaction) {
+ final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
+ if (callbacks == null) {
+ // No callbacks to execute, return early.
+ return;
+ }
+ log("Resolving callbacks");
+
+ final IBinder token = transaction.getActivityToken();
+ ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
+ final int size = callbacks.size();
+ for (int i = 0; i < size; ++i) {
+ final ClientTransactionItem item = callbacks.get(i);
+ log("Resolving callback: " + item);
+ final int preExecutionState = item.getPreExecutionState();
+ if (preExecutionState != UNDEFINED) {
+ cycleToPath(r, preExecutionState);
+ }
+
+ item.execute(mTransactionHandler, token, mPendingActions);
+ item.postExecute(mTransactionHandler, token, mPendingActions);
+ if (r == null) {
+ // Launch activity request will create an activity record.
+ r = mTransactionHandler.getActivityClient(token);
+ }
+
+ final int postExecutionState = item.getPostExecutionState();
+ if (postExecutionState != UNDEFINED) {
+ cycleToPath(r, postExecutionState);
+ }
+ }
+ }
+
+ /** Transition to the final state if requested by the transaction. */
+ private void executeLifecycleState(ClientTransaction transaction) {
+ final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
+ if (lifecycleItem == null) {
+ // No lifecycle request, return early.
+ return;
+ }
+ log("Resolving lifecycle state: " + lifecycleItem);
+
+ final IBinder token = transaction.getActivityToken();
+ final ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
+
+ // Cycle to the state right before the final requested state.
+ cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */);
+
+ // Execute the final transition with proper parameters.
+ lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
+ lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
+ }
+
+ /** Transition the client between states. */
+ @VisibleForTesting
+ public void cycleToPath(ActivityClientRecord r, int finish) {
+ cycleToPath(r, finish, false /* excludeLastState */);
+ }
+
+ /**
+ * Transition the client between states with an option not to perform the last hop in the
+ * sequence. This is used when resolving lifecycle state request, when the last transition must
+ * be performed with some specific parameters.
+ */
+ private void cycleToPath(ActivityClientRecord r, int finish,
+ boolean excludeLastState) {
+ final int start = r.getLifecycleState();
+ log("Cycle from: " + start + " to: " + finish + " excludeLastState:" + excludeLastState);
+ initLifecyclePath(start, finish, excludeLastState);
+ performLifecycleSequence(r);
+ }
+
+ /** Transition the client through previously initialized state sequence. */
+ private void performLifecycleSequence(ActivityClientRecord r) {
+ final int size = mLifecycleSequence.size();
+ for (int i = 0, state; i < size; i++) {
+ state = mLifecycleSequence.get(i);
+ log("Transitioning to state: " + state);
+ switch (state) {
+ case ON_CREATE:
+ mTransactionHandler.handleLaunchActivity(r, mPendingActions);
+ break;
+ case ON_START:
+ mTransactionHandler.handleStartActivity(r, mPendingActions);
+ break;
+ case ON_RESUME:
+ mTransactionHandler.handleResumeActivity(r.token, false /* clearHide */,
+ r.isForward, "LIFECYCLER_RESUME_ACTIVITY");
+ break;
+ case ON_PAUSE:
+ mTransactionHandler.handlePauseActivity(r.token, false /* finished */,
+ false /* userLeaving */, 0 /* configChanges */,
+ true /* dontReport */, mPendingActions);
+ break;
+ case ON_STOP:
+ mTransactionHandler.handleStopActivity(r.token, false /* show */,
+ 0 /* configChanges */, mPendingActions);
+ break;
+ case ON_DESTROY:
+ mTransactionHandler.handleDestroyActivity(r.token, false /* finishing */,
+ 0 /* configChanges */, false /* getNonConfigInstance */);
+ break;
+ case ON_RESTART:
+ mTransactionHandler.performRestartActivity(r.token, false /* start */);
+ break;
+ default:
+ throw new IllegalArgumentException("Unexpected lifecycle state: " + state);
+ }
+ }
+ }
+
+ /**
+ * Calculate the path through main lifecycle states for an activity and fill
+ * @link #mLifecycleSequence} with values starting with the state that follows the initial
+ * state.
+ */
+ public void initLifecyclePath(int start, int finish, boolean excludeLastState) {
+ mLifecycleSequence.clear();
+ if (finish >= start) {
+ // just go there
+ for (int i = start + 1; i <= finish; i++) {
+ mLifecycleSequence.add(i);
+ }
+ } else { // finish < start, can't just cycle down
+ if (start == ON_PAUSE && finish == ON_RESUME) {
+ // Special case when we can just directly go to resumed state.
+ mLifecycleSequence.add(ON_RESUME);
+ } else if (start <= ON_STOP && finish >= ON_START) {
+ // Restart and go to required state.
+
+ // Go to stopped state first.
+ for (int i = start + 1; i <= ON_STOP; i++) {
+ mLifecycleSequence.add(i);
+ }
+ // Restart
+ mLifecycleSequence.add(ON_RESTART);
+ // Go to required state
+ for (int i = ON_START; i <= finish; i++) {
+ mLifecycleSequence.add(i);
+ }
+ } else {
+ // Relaunch and go to required state
+
+ // Go to destroyed state first.
+ for (int i = start + 1; i <= ON_DESTROY; i++) {
+ mLifecycleSequence.add(i);
+ }
+ // Go to required state
+ for (int i = ON_CREATE; i <= finish; i++) {
+ mLifecycleSequence.add(i);
+ }
+ }
+ }
+
+ // Remove last transition in case we want to perform it with some specific params.
+ if (excludeLastState && mLifecycleSequence.size() != 0) {
+ mLifecycleSequence.remove(mLifecycleSequence.size() - 1);
+ }
+ }
+
+ @VisibleForTesting
+ public int[] getLifecycleSequence() {
+ return mLifecycleSequence.toArray();
+ }
+
+ private static void log(String message) {
+ if (DEBUG_RESOLVER) Slog.d(TAG, message);
+ }
+}
diff --git a/core/java/android/app/servertransaction/WindowVisibilityItem.java b/core/java/android/app/servertransaction/WindowVisibilityItem.java
new file mode 100644
index 0000000..d9956b1
--- /dev/null
+++ b/core/java/android/app/servertransaction/WindowVisibilityItem.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+
+import android.app.ClientTransactionHandler;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Trace;
+
+/**
+ * Window visibility change message.
+ * @hide
+ */
+public class WindowVisibilityItem extends ClientTransactionItem {
+
+ private boolean mShowWindow;
+
+ @Override
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityShowWindow");
+ client.handleWindowVisibility(token, mShowWindow);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+ }
+
+
+ // ObjectPoolItem implementation
+
+ private WindowVisibilityItem() {}
+
+ /** Obtain an instance initialized with provided params. */
+ public static WindowVisibilityItem obtain(boolean showWindow) {
+ WindowVisibilityItem instance = ObjectPool.obtain(WindowVisibilityItem.class);
+ if (instance == null) {
+ instance = new WindowVisibilityItem();
+ }
+ instance.mShowWindow = showWindow;
+
+ return instance;
+ }
+
+ @Override
+ public void recycle() {
+ mShowWindow = false;
+ ObjectPool.recycle(this);
+ }
+
+
+ // Parcelable implementation
+
+ /** Write to Parcel. */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBoolean(mShowWindow);
+ }
+
+ /** Read from Parcel. */
+ private WindowVisibilityItem(Parcel in) {
+ mShowWindow = in.readBoolean();
+ }
+
+ public static final Creator<WindowVisibilityItem> CREATOR =
+ new Creator<WindowVisibilityItem>() {
+ public WindowVisibilityItem createFromParcel(Parcel in) {
+ return new WindowVisibilityItem(in);
+ }
+
+ public WindowVisibilityItem[] newArray(int size) {
+ return new WindowVisibilityItem[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final WindowVisibilityItem other = (WindowVisibilityItem) o;
+ return mShowWindow == other.mShowWindow;
+ }
+
+ @Override
+ public int hashCode() {
+ return 17 + 31 * (mShowWindow ? 1 : 0);
+ }
+
+ @Override
+ public String toString() {
+ return "WindowVisibilityItem{showWindow=" + mShowWindow + "}";
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/core/java/android/app/slice/ISliceManager.aidl
similarity index 64%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to core/java/android/app/slice/ISliceManager.aidl
index 4ccdea5..6e52f38 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/core/java/android/app/slice/ISliceManager.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
+/**
+ * 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
+ * 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,
@@ -14,11 +14,8 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+package android.app.slice;
-import android.telephony.SubscriptionInfo;
-
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
+/** @hide */
+interface ISliceManager {
}
-
diff --git a/core/java/android/app/slice/SliceItem.java b/core/java/android/app/slice/SliceItem.java
index 8d81199..cdeee35 100644
--- a/core/java/android/app/slice/SliceItem.java
+++ b/core/java/android/app/slice/SliceItem.java
@@ -216,7 +216,7 @@
* @return The slice held by this {@link #FORMAT_ACTION} or {@link #FORMAT_SLICE} SliceItem
*/
public Slice getSlice() {
- if (getFormat() == FORMAT_ACTION) {
+ if (FORMAT_ACTION.equals(getFormat())) {
return ((Pair<PendingIntent, Slice>) mObj).second;
}
return (Slice) mObj;
diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java
new file mode 100644
index 0000000..e99f676
--- /dev/null
+++ b/core/java/android/app/slice/SliceManager.java
@@ -0,0 +1,39 @@
+/*
+ * 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 android.app.slice;
+
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.Handler;
+import android.os.ServiceManager;
+import android.os.ServiceManager.ServiceNotFoundException;
+
+/**
+ * @hide
+ */
+@SystemService(Context.SLICE_SERVICE)
+public class SliceManager {
+
+ private final ISliceManager mService;
+ private final Context mContext;
+
+ public SliceManager(Context context, Handler handler) throws ServiceNotFoundException {
+ mContext = context;
+ mService = ISliceManager.Stub.asInterface(
+ ServiceManager.getServiceOrThrow(Context.SLICE_SERVICE));
+ }
+}
diff --git a/core/java/android/app/usage/AppStandby.java b/core/java/android/app/usage/AppStandby.java
deleted file mode 100644
index 6f9fc2f..0000000
--- a/core/java/android/app/usage/AppStandby.java
+++ /dev/null
@@ -1,83 +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 android.app.usage;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Set of constants for app standby buckets and reasons. Apps will be moved into different buckets
- * that affect how frequently they can run in the background or perform other battery-consuming
- * actions. Buckets will be assigned based on how frequently or when the system thinks the user
- * is likely to use the app.
- * @hide
- */
-public class AppStandby {
-
- /** The app was used very recently, currently in use or likely to be used very soon. */
- public static final int STANDBY_BUCKET_ACTIVE = 0;
-
- // Leave some gap in case we want to increase the number of buckets
-
- /** The app was used recently and/or likely to be used in the next few hours */
- public static final int STANDBY_BUCKET_WORKING_SET = 3;
-
- // Leave some gap in case we want to increase the number of buckets
-
- /** The app was used in the last few days and/or likely to be used in the next few days */
- public static final int STANDBY_BUCKET_FREQUENT = 6;
-
- // Leave some gap in case we want to increase the number of buckets
-
- /** The app has not be used for several days and/or is unlikely to be used for several days */
- public static final int STANDBY_BUCKET_RARE = 9;
-
- // Leave some gap in case we want to increase the number of buckets
-
- /** The app has never been used. */
- public static final int STANDBY_BUCKET_NEVER = 12;
-
- /** Reason for bucketing -- default initial state */
- public static final String REASON_DEFAULT = "default";
-
- /** Reason for bucketing -- timeout */
- public static final String REASON_TIMEOUT = "timeout";
-
- /** Reason for bucketing -- usage */
- public static final String REASON_USAGE = "usage";
-
- /** Reason for bucketing -- forced by user / shell command */
- public static final String REASON_FORCED = "forced";
-
- /**
- * Reason for bucketing -- predicted. This is a prefix and the UID of the bucketeer will
- * be appended.
- */
- public static final String REASON_PREDICTED = "predicted";
-
- @IntDef(flag = false, value = {
- STANDBY_BUCKET_ACTIVE,
- STANDBY_BUCKET_WORKING_SET,
- STANDBY_BUCKET_FREQUENT,
- STANDBY_BUCKET_RARE,
- STANDBY_BUCKET_NEVER,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface StandbyBuckets {}
-}
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 3a3e16e..d614b20 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -16,16 +16,18 @@
package android.app.usage;
+import android.annotation.IntDef;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
-import android.app.usage.AppStandby.StandbyBuckets;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -90,6 +92,76 @@
*/
public static final int INTERVAL_COUNT = 4;
+
+ /**
+ * The app is whitelisted for some reason and the bucket cannot be changed.
+ * {@hide}
+ */
+ @SystemApi
+ public static final int STANDBY_BUCKET_EXEMPTED = 5;
+
+ /**
+ * The app was used very recently, currently in use or likely to be used very soon.
+ * @see #getAppStandbyBucket()
+ */
+ public static final int STANDBY_BUCKET_ACTIVE = 10;
+
+ /**
+ * The app was used recently and/or likely to be used in the next few hours.
+ * @see #getAppStandbyBucket()
+ */
+ public static final int STANDBY_BUCKET_WORKING_SET = 20;
+
+ /**
+ * The app was used in the last few days and/or likely to be used in the next few days.
+ * @see #getAppStandbyBucket()
+ */
+ public static final int STANDBY_BUCKET_FREQUENT = 30;
+
+ /**
+ * The app has not be used for several days and/or is unlikely to be used for several days.
+ * @see #getAppStandbyBucket()
+ */
+ public static final int STANDBY_BUCKET_RARE = 40;
+
+ /**
+ * The app has never been used.
+ * {@hide}
+ */
+ @SystemApi
+ public static final int STANDBY_BUCKET_NEVER = 50;
+
+ /** {@hide} Reason for bucketing -- default initial state */
+ public static final String REASON_DEFAULT = "default";
+
+ /** {@hide} Reason for bucketing -- timeout */
+ public static final String REASON_TIMEOUT = "timeout";
+
+ /** {@hide} Reason for bucketing -- usage */
+ public static final String REASON_USAGE = "usage";
+
+ /** {@hide} Reason for bucketing -- forced by user / shell command */
+ public static final String REASON_FORCED = "forced";
+
+ /**
+ * {@hide}
+ * Reason for bucketing -- predicted. This is a prefix and the UID of the bucketeer will
+ * be appended.
+ */
+ public static final String REASON_PREDICTED = "predicted";
+
+ /** @hide */
+ @IntDef(flag = false, value = {
+ STANDBY_BUCKET_EXEMPTED,
+ STANDBY_BUCKET_ACTIVE,
+ STANDBY_BUCKET_WORKING_SET,
+ STANDBY_BUCKET_FREQUENT,
+ STANDBY_BUCKET_RARE,
+ STANDBY_BUCKET_NEVER,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StandbyBuckets {}
+
private static final UsageEvents sEmptyResults = new UsageEvents();
private final Context mContext;
@@ -237,7 +309,7 @@
}
/**
- * @hide
+ * {@hide}
*/
public void setAppInactive(String packageName, boolean inactive) {
try {
@@ -248,19 +320,45 @@
}
/**
- * @hide
+ * Returns the current standby bucket of the calling app. The system determines the standby
+ * state of the app based on app usage patterns. Standby buckets determine how much an app will
+ * be restricted from running background tasks such as jobs, alarms and certain PendingIntent
+ * callbacks.
+ * Restrictions increase progressively from {@link #STANDBY_BUCKET_ACTIVE} to
+ * {@link #STANDBY_BUCKET_RARE}, with {@link #STANDBY_BUCKET_ACTIVE} being the least
+ * restrictive. The battery level of the device might also affect the restrictions.
+ *
+ * @return the current standby bucket of the calling app.
*/
+ public @StandbyBuckets int getAppStandbyBucket() {
+ try {
+ return mService.getAppStandbyBucket(mContext.getOpPackageName(),
+ mContext.getOpPackageName(),
+ mContext.getUserId());
+ } catch (RemoteException e) {
+ }
+ return STANDBY_BUCKET_ACTIVE;
+ }
+
+ /**
+ * {@hide}
+ * Returns the current standby bucket of the specified app. The caller must hold the permission
+ * android.permission.PACKAGE_USAGE_STATS.
+ * @param packageName the package for which to fetch the current standby bucket.
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
public @StandbyBuckets int getAppStandbyBucket(String packageName) {
try {
return mService.getAppStandbyBucket(packageName, mContext.getOpPackageName(),
mContext.getUserId());
} catch (RemoteException e) {
}
- return AppStandby.STANDBY_BUCKET_ACTIVE;
+ return STANDBY_BUCKET_ACTIVE;
}
/**
- * @hide
+ * {@hide}
* Changes the app standby state to the provided bucket.
*/
@SystemApi
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index 9954484f..4b4fe72 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -16,7 +16,7 @@
package android.app.usage;
-import android.app.usage.AppStandby.StandbyBuckets;
+import android.app.usage.UsageStatsManager.StandbyBuckets;
import android.content.ComponentName;
import android.content.res.Configuration;
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index fd1b0e0..75ce4fb 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -17,15 +17,17 @@
package android.appwidget;
import android.annotation.NonNull;
+import android.app.PendingIntent;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.ResourceId;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-import android.content.ComponentName;
import android.os.UserHandle;
import android.util.DisplayMetrics;
import android.util.TypedValue;
@@ -69,6 +71,23 @@
public static final int WIDGET_CATEGORY_SEARCHBOX = 4;
/**
+ * The widget can be reconfigured anytime after it is bound by starting the
+ * {@link #configure} activity.
+ *
+ * @see #widgetFeatures
+ */
+ public static final int WIDGET_FEATURE_RECONFIGURABLE = 1;
+
+ /**
+ * The widget is added directly by the app, and the host may hide this widget when providing
+ * the user with the list of available widgets to choose from.
+ *
+ * @see AppWidgetManager#requestPinAppWidget(ComponentName, Bundle, PendingIntent)
+ * @see #widgetFeatures
+ */
+ public static final int WIDGET_FEATURE_HIDE_FROM_PICKER = 2;
+
+ /**
* Identity of this AppWidget component. This component should be a {@link
* android.content.BroadcastReceiver}, and it will be sent the AppWidget intents
* {@link android.appwidget as described in the AppWidget package documentation}.
@@ -209,6 +228,15 @@
*/
public int widgetCategory;
+ /**
+ * Flags indicating various features supported by the widget. These are hints to the widget
+ * host, and do not actually change the behavior of the widget.
+ *
+ * @see #WIDGET_FEATURE_RECONFIGURABLE
+ * @see #WIDGET_FEATURE_HIDE_FROM_PICKER
+ */
+ public int widgetFeatures;
+
/** @hide */
public ActivityInfo providerInfo;
@@ -221,9 +249,7 @@
*/
@SuppressWarnings("deprecation")
public AppWidgetProviderInfo(Parcel in) {
- if (0 != in.readInt()) {
- this.provider = new ComponentName(in);
- }
+ this.provider = in.readTypedObject(ComponentName.CREATOR);
this.minWidth = in.readInt();
this.minHeight = in.readInt();
this.minResizeWidth = in.readInt();
@@ -231,16 +257,15 @@
this.updatePeriodMillis = in.readInt();
this.initialLayout = in.readInt();
this.initialKeyguardLayout = in.readInt();
- if (0 != in.readInt()) {
- this.configure = new ComponentName(in);
- }
+ this.configure = in.readTypedObject(ComponentName.CREATOR);
this.label = in.readString();
this.icon = in.readInt();
this.previewImage = in.readInt();
this.autoAdvanceViewId = in.readInt();
this.resizeMode = in.readInt();
this.widgetCategory = in.readInt();
- this.providerInfo = in.readParcelable(null);
+ this.providerInfo = in.readTypedObject(ActivityInfo.CREATOR);
+ this.widgetFeatures = in.readInt();
}
/**
@@ -308,13 +333,8 @@
@Override
@SuppressWarnings("deprecation")
- public void writeToParcel(android.os.Parcel out, int flags) {
- if (this.provider != null) {
- out.writeInt(1);
- this.provider.writeToParcel(out, flags);
- } else {
- out.writeInt(0);
- }
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeTypedObject(this.provider, flags);
out.writeInt(this.minWidth);
out.writeInt(this.minHeight);
out.writeInt(this.minResizeWidth);
@@ -322,19 +342,15 @@
out.writeInt(this.updatePeriodMillis);
out.writeInt(this.initialLayout);
out.writeInt(this.initialKeyguardLayout);
- if (this.configure != null) {
- out.writeInt(1);
- this.configure.writeToParcel(out, flags);
- } else {
- out.writeInt(0);
- }
+ out.writeTypedObject(this.configure, flags);
out.writeString(this.label);
out.writeInt(this.icon);
out.writeInt(this.previewImage);
out.writeInt(this.autoAdvanceViewId);
out.writeInt(this.resizeMode);
out.writeInt(this.widgetCategory);
- out.writeParcelable(this.providerInfo, flags);
+ out.writeTypedObject(this.providerInfo, flags);
+ out.writeInt(this.widgetFeatures);
}
@Override
@@ -357,6 +373,7 @@
that.resizeMode = this.resizeMode;
that.widgetCategory = this.widgetCategory;
that.providerInfo = this.providerInfo;
+ that.widgetFeatures = this.widgetFeatures;
return that;
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 578a5b8..c7be0f3 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2009-2016 The Android Open Source Project
- * Copyright (C) 2015 Samsung LSI
+ * Copyright 2009-2016 The Android Open Source Project
+ * Copyright 2015 Samsung LSI
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -132,9 +132,8 @@
* respectively.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_STATE_CHANGED =
- "android.bluetooth.adapter.action.STATE_CHANGED";
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
+ ACTION_STATE_CHANGED = "android.bluetooth.adapter.action.STATE_CHANGED";
/**
* Used as an int extra field in {@link #ACTION_STATE_CHANGED}
@@ -144,8 +143,7 @@
* {@link #STATE_ON},
* {@link #STATE_TURNING_OFF},
*/
- public static final String EXTRA_STATE =
- "android.bluetooth.adapter.extra.STATE";
+ public static final String EXTRA_STATE = "android.bluetooth.adapter.extra.STATE";
/**
* Used as an int extra field in {@link #ACTION_STATE_CHANGED}
* intents to request the previous power state. Possible values are:
@@ -158,11 +156,17 @@
"android.bluetooth.adapter.extra.PREVIOUS_STATE";
/** @hide */
- @IntDef({STATE_OFF, STATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF, STATE_BLE_TURNING_ON,
- STATE_BLE_ON, STATE_BLE_TURNING_OFF})
+ @IntDef({
+ STATE_OFF,
+ STATE_TURNING_ON,
+ STATE_ON,
+ STATE_TURNING_OFF,
+ STATE_BLE_TURNING_ON,
+ STATE_BLE_ON,
+ STATE_BLE_TURNING_OFF
+ })
@Retention(RetentionPolicy.SOURCE)
- public @interface AdapterState {
- }
+ public @interface AdapterState {}
/**
* Indicates the local Bluetooth adapter is off.
@@ -254,9 +258,8 @@
* application can be notified when the device has ended discoverability.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*/
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_REQUEST_DISCOVERABLE =
- "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String
+ ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
/**
* Used as an optional int extra field in {@link
@@ -282,9 +285,8 @@
* for global notification whenever Bluetooth is turned on or off.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*/
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_REQUEST_ENABLE =
- "android.bluetooth.adapter.action.REQUEST_ENABLE";
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String
+ ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE";
/**
* Activity Action: Show a system activity that allows the user to turn off
@@ -305,9 +307,8 @@
*
* @hide
*/
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_REQUEST_DISABLE =
- "android.bluetooth.adapter.action.REQUEST_DISABLE";
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String
+ ACTION_REQUEST_DISABLE = "android.bluetooth.adapter.action.REQUEST_DISABLE";
/**
* Activity Action: Show a system activity that allows user to enable BLE scans even when
@@ -334,9 +335,8 @@
* respectively.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*/
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_SCAN_MODE_CHANGED =
- "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
+ ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
/**
* Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
@@ -359,8 +359,7 @@
/** @hide */
@IntDef({SCAN_MODE_NONE, SCAN_MODE_CONNECTABLE, SCAN_MODE_CONNECTABLE_DISCOVERABLE})
@Retention(RetentionPolicy.SOURCE)
- public @interface ScanMode {
- }
+ public @interface ScanMode {}
/**
* Indicates that both inquiry scan and page scan are disabled on the local
@@ -396,17 +395,15 @@
* discovery.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_DISCOVERY_STARTED =
- "android.bluetooth.adapter.action.DISCOVERY_STARTED";
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
+ ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
/**
* Broadcast Action: The local Bluetooth adapter has finished the device
* discovery process.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_DISCOVERY_FINISHED =
- "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
+ ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
/**
* Broadcast Action: The local Bluetooth adapter has changed its friendly
@@ -416,9 +413,8 @@
* the name.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_LOCAL_NAME_CHANGED =
- "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
+ ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
/**
* Used as a String extra field in {@link #ACTION_LOCAL_NAME_CHANGED}
* intents to request the local Bluetooth name.
@@ -451,8 +447,8 @@
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_STATE_CHANGED =
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
+ ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
/**
@@ -476,8 +472,7 @@
*
* @hide
*/
- @SystemApi
- public static final String ACTION_BLE_STATE_CHANGED =
+ @SystemApi public static final String ACTION_BLE_STATE_CHANGED =
"android.bluetooth.adapter.action.BLE_STATE_CHANGED";
/**
@@ -574,8 +569,7 @@
private final IBluetoothManager mManagerService;
private IBluetooth mService;
- private final ReentrantReadWriteLock mServiceLock =
- new ReentrantReadWriteLock();
+ private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
private final Object mLock = new Object();
private final Map<LeScanCallback, ScanCallback> mLeScanClients;
@@ -655,8 +649,9 @@
if (address == null || address.length != 6) {
throw new IllegalArgumentException("Bluetooth address must have 6 bytes");
}
- return new BluetoothDevice(String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
- address[0], address[1], address[2], address[3], address[4], address[5]));
+ return new BluetoothDevice(
+ String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", address[0], address[1],
+ address[2], address[3], address[4], address[5]));
}
/**
@@ -668,7 +663,9 @@
* on this device before calling this method.
*/
public BluetoothLeAdvertiser getBluetoothLeAdvertiser() {
- if (!getLeAccess()) return null;
+ if (!getLeAccess()) {
+ return null;
+ }
synchronized (mLock) {
if (sBluetoothLeAdvertiser == null) {
sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService);
@@ -698,8 +695,7 @@
synchronized (mLock) {
if (sPeriodicAdvertisingManager == null) {
- sPeriodicAdvertisingManager =
- new PeriodicAdvertisingManager(mManagerService);
+ sPeriodicAdvertisingManager = new PeriodicAdvertisingManager(mManagerService);
}
}
return sPeriodicAdvertisingManager;
@@ -709,7 +705,9 @@
* Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations.
*/
public BluetoothLeScanner getBluetoothLeScanner() {
- if (!getLeAccess()) return null;
+ if (!getLeAccess()) {
+ return null;
+ }
synchronized (mLock) {
if (sBluetoothLeScanner == null) {
sBluetoothLeScanner = new BluetoothLeScanner(mManagerService);
@@ -729,7 +727,9 @@
public boolean isEnabled() {
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.isEnabled();
+ if (mService != null) {
+ return mService.isEnabled();
+ }
} catch (RemoteException e) {
Log.e(TAG, "", e);
} finally {
@@ -750,7 +750,9 @@
@SystemApi
public boolean isLeEnabled() {
final int state = getLeState();
- if (DBG) Log.d(TAG, "isLeEnabled(): " + BluetoothAdapter.nameForState(state));
+ if (DBG) {
+ Log.d(TAG, "isLeEnabled(): " + BluetoothAdapter.nameForState(state));
+ }
return (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON);
}
@@ -781,12 +783,16 @@
*/
@SystemApi
public boolean disableBLE() {
- if (!isBleScanAlwaysAvailable()) return false;
+ if (!isBleScanAlwaysAvailable()) {
+ return false;
+ }
int state = getLeState();
if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON) {
String packageName = ActivityThread.currentPackageName();
- if (DBG) Log.d(TAG, "disableBLE(): de-registering " + packageName);
+ if (DBG) {
+ Log.d(TAG, "disableBLE(): de-registering " + packageName);
+ }
try {
mManagerService.updateBleAppCount(mToken, false, packageName);
} catch (RemoteException e) {
@@ -795,7 +801,9 @@
return true;
}
- if (DBG) Log.d(TAG, "disableBLE(): Already disabled");
+ if (DBG) {
+ Log.d(TAG, "disableBLE(): Already disabled");
+ }
return false;
}
@@ -832,16 +840,22 @@
*/
@SystemApi
public boolean enableBLE() {
- if (!isBleScanAlwaysAvailable()) return false;
+ if (!isBleScanAlwaysAvailable()) {
+ return false;
+ }
try {
String packageName = ActivityThread.currentPackageName();
mManagerService.updateBleAppCount(mToken, true, packageName);
if (isLeEnabled()) {
- if (DBG) Log.d(TAG, "enableBLE(): Bluetooth already enabled");
+ if (DBG) {
+ Log.d(TAG, "enableBLE(): Bluetooth already enabled");
+ }
return true;
}
- if (DBG) Log.d(TAG, "enableBLE(): Calling enable");
+ if (DBG) {
+ Log.d(TAG, "enableBLE(): Calling enable");
+ }
return mManagerService.enable(packageName);
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -877,19 +891,16 @@
}
// Consider all internal states as OFF
- if (state == BluetoothAdapter.STATE_BLE_ON
- || state == BluetoothAdapter.STATE_BLE_TURNING_ON
+ if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON
|| state == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
if (VDBG) {
- Log.d(TAG,
- "Consider " + BluetoothAdapter.nameForState(state) + " state as OFF");
+ Log.d(TAG, "Consider " + BluetoothAdapter.nameForState(state) + " state as OFF");
}
state = BluetoothAdapter.STATE_OFF;
}
if (VDBG) {
- Log.d(TAG,
- "" + hashCode() + ": getState(). Returning " + BluetoothAdapter.nameForState(
- state));
+ Log.d(TAG, "" + hashCode() + ": getState(). Returning " + BluetoothAdapter.nameForState(
+ state));
}
return state;
}
@@ -926,7 +937,9 @@
mServiceLock.readLock().unlock();
}
- if (VDBG) Log.d(TAG, "getLeState() returning " + BluetoothAdapter.nameForState(state));
+ if (VDBG) {
+ Log.d(TAG, "getLeState() returning " + BluetoothAdapter.nameForState(state));
+ }
return state;
}
@@ -967,7 +980,9 @@
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean enable() {
if (isEnabled()) {
- if (DBG) Log.d(TAG, "enable(): BT already enabled!");
+ if (DBG) {
+ Log.d(TAG, "enable(): BT already enabled!");
+ }
return true;
}
try {
@@ -1093,10 +1108,14 @@
* @hide
*/
public ParcelUuid[] getUuids() {
- if (getState() != STATE_ON) return null;
+ if (getState() != STATE_ON) {
+ return null;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.getUuids();
+ if (mService != null) {
+ return mService.getUuids();
+ }
} catch (RemoteException e) {
Log.e(TAG, "", e);
} finally {
@@ -1121,10 +1140,14 @@
*/
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean setName(String name) {
- if (getState() != STATE_ON) return false;
+ if (getState() != STATE_ON) {
+ return false;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.setName(name);
+ if (mService != null) {
+ return mService.setName(name);
+ }
} catch (RemoteException e) {
Log.e(TAG, "", e);
} finally {
@@ -1143,10 +1166,14 @@
*/
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public BluetoothClass getBluetoothClass() {
- if (getState() != STATE_ON) return null;
+ if (getState() != STATE_ON) {
+ return null;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.getBluetoothClass();
+ if (mService != null) {
+ return mService.getBluetoothClass();
+ }
} catch (RemoteException e) {
Log.e(TAG, "", e);
} finally {
@@ -1168,10 +1195,14 @@
*/
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setBluetoothClass(BluetoothClass bluetoothClass) {
- if (getState() != STATE_ON) return false;
+ if (getState() != STATE_ON) {
+ return false;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.setBluetoothClass(bluetoothClass);
+ if (mService != null) {
+ return mService.setBluetoothClass(bluetoothClass);
+ }
} catch (RemoteException e) {
Log.e(TAG, "", e);
} finally {
@@ -1198,10 +1229,14 @@
@RequiresPermission(Manifest.permission.BLUETOOTH)
@ScanMode
public int getScanMode() {
- if (getState() != STATE_ON) return SCAN_MODE_NONE;
+ if (getState() != STATE_ON) {
+ return SCAN_MODE_NONE;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.getScanMode();
+ if (mService != null) {
+ return mService.getScanMode();
+ }
} catch (RemoteException e) {
Log.e(TAG, "", e);
} finally {
@@ -1239,10 +1274,14 @@
* @hide
*/
public boolean setScanMode(@ScanMode int mode, int duration) {
- if (getState() != STATE_ON) return false;
+ if (getState() != STATE_ON) {
+ return false;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.setScanMode(mode, duration);
+ if (mService != null) {
+ return mService.setScanMode(mode, duration);
+ }
} catch (RemoteException e) {
Log.e(TAG, "", e);
} finally {
@@ -1253,17 +1292,23 @@
/** @hide */
public boolean setScanMode(int mode) {
- if (getState() != STATE_ON) return false;
+ if (getState() != STATE_ON) {
+ return false;
+ }
/* getDiscoverableTimeout() to use the latest from NV than use 0 */
return setScanMode(mode, getDiscoverableTimeout());
}
/** @hide */
public int getDiscoverableTimeout() {
- if (getState() != STATE_ON) return -1;
+ if (getState() != STATE_ON) {
+ return -1;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.getDiscoverableTimeout();
+ if (mService != null) {
+ return mService.getDiscoverableTimeout();
+ }
} catch (RemoteException e) {
Log.e(TAG, "", e);
} finally {
@@ -1274,10 +1319,14 @@
/** @hide */
public void setDiscoverableTimeout(int timeout) {
- if (getState() != STATE_ON) return;
+ if (getState() != STATE_ON) {
+ return;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) mService.setDiscoverableTimeout(timeout);
+ if (mService != null) {
+ mService.setDiscoverableTimeout(timeout);
+ }
} catch (RemoteException e) {
Log.e(TAG, "", e);
} finally {
@@ -1296,7 +1345,9 @@
public long getDiscoveryEndMillis() {
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.getDiscoveryEndMillis();
+ if (mService != null) {
+ return mService.getDiscoveryEndMillis();
+ }
} catch (RemoteException e) {
Log.e(TAG, "", e);
} finally {
@@ -1336,10 +1387,14 @@
*/
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean startDiscovery() {
- if (getState() != STATE_ON) return false;
+ if (getState() != STATE_ON) {
+ return false;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.startDiscovery();
+ if (mService != null) {
+ return mService.startDiscovery();
+ }
} catch (RemoteException e) {
Log.e(TAG, "", e);
} finally {
@@ -1366,10 +1421,14 @@
*/
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean cancelDiscovery() {
- if (getState() != STATE_ON) return false;
+ if (getState() != STATE_ON) {
+ return false;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.cancelDiscovery();
+ if (mService != null) {
+ return mService.cancelDiscovery();
+ }
} catch (RemoteException e) {
Log.e(TAG, "", e);
} finally {
@@ -1398,10 +1457,14 @@
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
public boolean isDiscovering() {
- if (getState() != STATE_ON) return false;
+ if (getState() != STATE_ON) {
+ return false;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.isDiscovering();
+ if (mService != null) {
+ return mService.isDiscovering();
+ }
} catch (RemoteException e) {
Log.e(TAG, "", e);
} finally {
@@ -1416,10 +1479,14 @@
* @return true if Multiple Advertisement feature is supported
*/
public boolean isMultipleAdvertisementSupported() {
- if (getState() != STATE_ON) return false;
+ if (getState() != STATE_ON) {
+ return false;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.isMultiAdvertisementSupported();
+ if (mService != null) {
+ return mService.isMultiAdvertisementSupported();
+ }
} catch (RemoteException e) {
Log.e(TAG, "failed to get isMultipleAdvertisementSupported, error: ", e);
} finally {
@@ -1454,10 +1521,14 @@
* @return true if chipset supports on-chip filtering
*/
public boolean isOffloadedFilteringSupported() {
- if (!getLeAccess()) return false;
+ if (!getLeAccess()) {
+ return false;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.isOffloadedFilteringSupported();
+ if (mService != null) {
+ return mService.isOffloadedFilteringSupported();
+ }
} catch (RemoteException e) {
Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e);
} finally {
@@ -1472,10 +1543,14 @@
* @return true if chipset supports on-chip scan batching
*/
public boolean isOffloadedScanBatchingSupported() {
- if (!getLeAccess()) return false;
+ if (!getLeAccess()) {
+ return false;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.isOffloadedScanBatchingSupported();
+ if (mService != null) {
+ return mService.isOffloadedScanBatchingSupported();
+ }
} catch (RemoteException e) {
Log.e(TAG, "failed to get isOffloadedScanBatchingSupported, error: ", e);
} finally {
@@ -1490,10 +1565,14 @@
* @return true if chipset supports LE 2M PHY feature
*/
public boolean isLe2MPhySupported() {
- if (!getLeAccess()) return false;
+ if (!getLeAccess()) {
+ return false;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.isLe2MPhySupported();
+ if (mService != null) {
+ return mService.isLe2MPhySupported();
+ }
} catch (RemoteException e) {
Log.e(TAG, "failed to get isExtendedAdvertisingSupported, error: ", e);
} finally {
@@ -1508,10 +1587,14 @@
* @return true if chipset supports LE Coded PHY feature
*/
public boolean isLeCodedPhySupported() {
- if (!getLeAccess()) return false;
+ if (!getLeAccess()) {
+ return false;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.isLeCodedPhySupported();
+ if (mService != null) {
+ return mService.isLeCodedPhySupported();
+ }
} catch (RemoteException e) {
Log.e(TAG, "failed to get isLeCodedPhySupported, error: ", e);
} finally {
@@ -1526,10 +1609,14 @@
* @return true if chipset supports LE Extended Advertising feature
*/
public boolean isLeExtendedAdvertisingSupported() {
- if (!getLeAccess()) return false;
+ if (!getLeAccess()) {
+ return false;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.isLeExtendedAdvertisingSupported();
+ if (mService != null) {
+ return mService.isLeExtendedAdvertisingSupported();
+ }
} catch (RemoteException e) {
Log.e(TAG, "failed to get isLeExtendedAdvertisingSupported, error: ", e);
} finally {
@@ -1544,10 +1631,14 @@
* @return true if chipset supports LE Periodic Advertising feature
*/
public boolean isLePeriodicAdvertisingSupported() {
- if (!getLeAccess()) return false;
+ if (!getLeAccess()) {
+ return false;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.isLePeriodicAdvertisingSupported();
+ if (mService != null) {
+ return mService.isLePeriodicAdvertisingSupported();
+ }
} catch (RemoteException e) {
Log.e(TAG, "failed to get isLePeriodicAdvertisingSupported, error: ", e);
} finally {
@@ -1563,10 +1654,14 @@
* @return the maximum LE advertising data length.
*/
public int getLeMaximumAdvertisingDataLength() {
- if (!getLeAccess()) return 0;
+ if (!getLeAccess()) {
+ return 0;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.getLeMaximumAdvertisingDataLength();
+ if (mService != null) {
+ return mService.getLeMaximumAdvertisingDataLength();
+ }
} catch (RemoteException e) {
Log.e(TAG, "failed to get getLeMaximumAdvertisingDataLength, error: ", e);
} finally {
@@ -1582,7 +1677,9 @@
* @hide
*/
public boolean isHardwareTrackingFiltersAvailable() {
- if (!getLeAccess()) return false;
+ if (!getLeAccess()) {
+ return false;
+ }
try {
IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
if (iGatt == null) {
@@ -1669,7 +1766,9 @@
}
try {
mServiceLock.readLock().lock();
- if (mService != null) return toDeviceSet(mService.getBondedDevices());
+ if (mService != null) {
+ return toDeviceSet(mService.getBondedDevices());
+ }
return toDeviceSet(new BluetoothDevice[0]);
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1723,10 +1822,14 @@
* @hide
*/
public int getConnectionState() {
- if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED;
+ if (getState() != STATE_ON) {
+ return BluetoothAdapter.STATE_DISCONNECTED;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.getAdapterConnectionState();
+ if (mService != null) {
+ return mService.getAdapterConnectionState();
+ }
} catch (RemoteException e) {
Log.e(TAG, "getConnectionState:", e);
} finally {
@@ -1750,10 +1853,14 @@
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
public int getProfileConnectionState(int profile) {
- if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED;
+ if (getState() != STATE_ON) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.getProfileConnectionState(profile);
+ if (mService != null) {
+ return mService.getProfileConnectionState(profile);
+ }
} catch (RemoteException e) {
Log.e(TAG, "getProfileConnectionState:", e);
} finally {
@@ -1790,7 +1897,7 @@
* <p>Valid RFCOMM channels are in range 1 to 30.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
* <p>To auto assign a channel without creating a SDP record use
- * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number.
+ * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number.
*
* @param channel RFCOMM channel to listen on
* @param mitm enforce man-in-the-middle protection for authentication.
@@ -1802,10 +1909,10 @@
* @hide
*/
public BluetoothServerSocket listenUsingRfcommOn(int channel, boolean mitm,
- boolean min16DigitPin)
- throws IOException {
- BluetoothServerSocket socket = new BluetoothServerSocket(
- BluetoothSocket.TYPE_RFCOMM, true, true, channel, mitm, min16DigitPin);
+ boolean min16DigitPin) throws IOException {
+ BluetoothServerSocket socket =
+ new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, true, true, channel, mitm,
+ min16DigitPin);
int errno = socket.mSocket.bindListen();
if (channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
socket.setChannel(socket.mSocket.getPort());
@@ -1913,8 +2020,8 @@
* permissions, or channel in use.
* @hide
*/
- public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(
- String name, UUID uuid) throws IOException {
+ public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(String name, UUID uuid)
+ throws IOException {
return createNewRfcommSocketAndRecord(name, uuid, false, true);
}
@@ -1922,8 +2029,8 @@
private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid,
boolean auth, boolean encrypt) throws IOException {
BluetoothServerSocket socket;
- socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth,
- encrypt, new ParcelUuid(uuid));
+ socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth, encrypt,
+ new ParcelUuid(uuid));
socket.setServiceName(name);
int errno = socket.mSocket.bindListen();
if (errno != 0) {
@@ -1945,8 +2052,8 @@
* @hide
*/
public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
- BluetoothServerSocket socket = new BluetoothServerSocket(
- BluetoothSocket.TYPE_RFCOMM, false, false, port);
+ BluetoothServerSocket socket =
+ new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, false, false, port);
int errno = socket.mSocket.bindListen();
if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
socket.setChannel(socket.mSocket.getPort());
@@ -1969,10 +2076,9 @@
* permissions.
* @hide
*/
- public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port)
- throws IOException {
- BluetoothServerSocket socket = new BluetoothServerSocket(
- BluetoothSocket.TYPE_RFCOMM, false, true, port);
+ public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port) throws IOException {
+ BluetoothServerSocket socket =
+ new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, false, true, port);
int errno = socket.mSocket.bindListen();
if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
socket.setChannel(socket.mSocket.getPort());
@@ -1996,8 +2102,8 @@
* @hide
*/
public static BluetoothServerSocket listenUsingScoOn() throws IOException {
- BluetoothServerSocket socket = new BluetoothServerSocket(
- BluetoothSocket.TYPE_SCO, false, false, -1);
+ BluetoothServerSocket socket =
+ new BluetoothServerSocket(BluetoothSocket.TYPE_SCO, false, false, -1);
int errno = socket.mSocket.bindListen();
if (errno < 0) {
//TODO(BT): Throw the same exception error code
@@ -2011,7 +2117,7 @@
* Construct an encrypted, authenticated, L2CAP server socket.
* Call #accept to retrieve connections to this socket.
* <p>To auto assign a port without creating a SDP record use
- * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
+ * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
*
* @param port the PSM to listen on
* @param mitm enforce man-in-the-middle protection for authentication.
@@ -2024,8 +2130,9 @@
*/
public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin)
throws IOException {
- BluetoothServerSocket socket = new BluetoothServerSocket(
- BluetoothSocket.TYPE_L2CAP, true, true, port, mitm, min16DigitPin);
+ BluetoothServerSocket socket =
+ new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP, true, true, port, mitm,
+ min16DigitPin);
int errno = socket.mSocket.bindListen();
if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
socket.setChannel(socket.mSocket.getPort());
@@ -2043,7 +2150,7 @@
* Construct an encrypted, authenticated, L2CAP server socket.
* Call #accept to retrieve connections to this socket.
* <p>To auto assign a port without creating a SDP record use
- * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
+ * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
*
* @param port the PSM to listen on
* @return An L2CAP BluetoothServerSocket
@@ -2060,7 +2167,7 @@
* Construct an insecure L2CAP server socket.
* Call #accept to retrieve connections to this socket.
* <p>To auto assign a port without creating a SDP record use
- * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
+ * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
*
* @param port the PSM to listen on
* @return An L2CAP BluetoothServerSocket
@@ -2069,8 +2176,9 @@
* @hide
*/
public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException {
- BluetoothServerSocket socket = new BluetoothServerSocket(
- BluetoothSocket.TYPE_L2CAP, false, false, port, false, false);
+ BluetoothServerSocket socket =
+ new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP, false, false, port, false,
+ false);
int errno = socket.mSocket.bindListen();
if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
socket.setChannel(socket.mSocket.getPort());
@@ -2114,7 +2222,9 @@
*/
public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
int profile) {
- if (context == null || listener == null) return false;
+ if (context == null || listener == null) {
+ return false;
+ }
if (profile == BluetoothProfile.HEADSET) {
BluetoothHeadset headset = new BluetoothHeadset(context, listener);
@@ -2172,7 +2282,9 @@
* @param proxy Profile proxy object
*/
public void closeProfileProxy(int profile, BluetoothProfile proxy) {
- if (proxy == null) return;
+ if (proxy == null) {
+ return;
+ }
switch (profile) {
case BluetoothProfile.HEADSET:
@@ -2241,7 +2353,9 @@
private final IBluetoothManagerCallback mManagerCallback =
new IBluetoothManagerCallback.Stub() {
public void onBluetoothServiceUp(IBluetooth bluetoothService) {
- if (DBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
+ if (DBG) {
+ Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
+ }
mServiceLock.writeLock().lock();
mService = bluetoothService;
@@ -2263,14 +2377,22 @@
}
public void onBluetoothServiceDown() {
- if (DBG) Log.d(TAG, "onBluetoothServiceDown: " + mService);
+ if (DBG) {
+ Log.d(TAG, "onBluetoothServiceDown: " + mService);
+ }
try {
mServiceLock.writeLock().lock();
mService = null;
- if (mLeScanClients != null) mLeScanClients.clear();
- if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup();
- if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup();
+ if (mLeScanClients != null) {
+ mLeScanClients.clear();
+ }
+ if (sBluetoothLeAdvertiser != null) {
+ sBluetoothLeAdvertiser.cleanup();
+ }
+ if (sBluetoothLeScanner != null) {
+ sBluetoothLeScanner.cleanup();
+ }
} finally {
mServiceLock.writeLock().unlock();
}
@@ -2291,7 +2413,9 @@
}
public void onBrEdrDown() {
- if (VDBG) Log.i(TAG, "onBrEdrDown: " + mService);
+ if (VDBG) {
+ Log.i(TAG, "onBrEdrDown: " + mService);
+ }
}
};
@@ -2305,7 +2429,9 @@
@RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
public boolean enableNoAutoConnect() {
if (isEnabled()) {
- if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT already enabled!");
+ if (DBG) {
+ Log.d(TAG, "enableNoAutoConnect(): BT already enabled!");
+ }
return true;
}
try {
@@ -2354,7 +2480,10 @@
* @hide
*/
public interface BluetoothStateChangeCallback {
- public void onBluetoothStateChange(boolean on);
+ /**
+ * @hide
+ */
+ void onBluetoothStateChange(boolean on);
}
/**
@@ -2363,8 +2492,7 @@
public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub {
private BluetoothStateChangeCallback mCallback;
- StateChangeCallbackWrapper(BluetoothStateChangeCallback
- callback) {
+ StateChangeCallbackWrapper(BluetoothStateChangeCallback callback) {
mCallback = callback;
}
@@ -2461,7 +2589,7 @@
* if no RSSI value is available.
* @param scanRecord The content of the advertisement record offered by the remote device.
*/
- public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord);
+ void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord);
}
/**
@@ -2497,20 +2625,28 @@
@Deprecated
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) {
- if (DBG) Log.d(TAG, "startLeScan(): " + Arrays.toString(serviceUuids));
+ if (DBG) {
+ Log.d(TAG, "startLeScan(): " + Arrays.toString(serviceUuids));
+ }
if (callback == null) {
- if (DBG) Log.e(TAG, "startLeScan: null callback");
+ if (DBG) {
+ Log.e(TAG, "startLeScan: null callback");
+ }
return false;
}
BluetoothLeScanner scanner = getBluetoothLeScanner();
if (scanner == null) {
- if (DBG) Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner");
+ if (DBG) {
+ Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner");
+ }
return false;
}
synchronized (mLeScanClients) {
if (mLeScanClients.containsKey(callback)) {
- if (DBG) Log.e(TAG, "LE Scan has already started");
+ if (DBG) {
+ Log.e(TAG, "LE Scan has already started");
+ }
return false;
}
@@ -2540,7 +2676,9 @@
}
List<ParcelUuid> scanServiceUuids = scanRecord.getServiceUuids();
if (scanServiceUuids == null || !scanServiceUuids.containsAll(uuids)) {
- if (DBG) Log.d(TAG, "uuids does not match");
+ if (DBG) {
+ Log.d(TAG, "uuids does not match");
+ }
return;
}
}
@@ -2548,16 +2686,18 @@
scanRecord.getBytes());
}
};
- ScanSettings settings = new ScanSettings.Builder()
- .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
- .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
+ ScanSettings settings = new ScanSettings.Builder().setCallbackType(
+ ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
+ .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
+ .build();
List<ScanFilter> filters = new ArrayList<ScanFilter>();
if (serviceUuids != null && serviceUuids.length > 0) {
// Note scan filter does not support matching an UUID array so we put one
// UUID to hardware and match the whole array in callback.
- ScanFilter filter = new ScanFilter.Builder().setServiceUuid(
- new ParcelUuid(serviceUuids[0])).build();
+ ScanFilter filter =
+ new ScanFilter.Builder().setServiceUuid(new ParcelUuid(serviceUuids[0]))
+ .build();
filters.add(filter);
}
scanner.startScan(filters, settings, scanCallback);
@@ -2582,7 +2722,9 @@
@Deprecated
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public void stopLeScan(LeScanCallback callback) {
- if (DBG) Log.d(TAG, "stopLeScan()");
+ if (DBG) {
+ Log.d(TAG, "stopLeScan()");
+ }
BluetoothLeScanner scanner = getBluetoothLeScanner();
if (scanner == null) {
return;
@@ -2590,7 +2732,9 @@
synchronized (mLeScanClients) {
ScanCallback scanCallback = mLeScanClients.remove(callback);
if (scanCallback == null) {
- if (DBG) Log.d(TAG, "scan not started yet");
+ if (DBG) {
+ Log.d(TAG, "scan not started yet");
+ }
return;
}
scanner.stopScan(scanCallback);
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 1241f23..838d315 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -678,33 +678,6 @@
}
/**
- * Get battery usage hint for Bluetooth Headset service.
- * This is a monotonically increasing integer. Wraps to 0 at
- * Integer.MAX_INT, and at boot.
- * Current implementation returns the number of AT commands handled since
- * boot. This is a good indicator for spammy headset/handsfree units that
- * can keep the device awake by polling for cellular status updates. As a
- * rule of thumb, each AT command prevents the CPU from sleeping for 500 ms
- *
- * @param device the bluetooth headset.
- * @return monotonically increasing battery usage hint, or a negative error code on error
- * @hide
- */
- public int getBatteryUsageHint(BluetoothDevice device) {
- if (VDBG) log("getBatteryUsageHint()");
- final IBluetoothHeadset service = mService;
- if (service != null && isEnabled() && isValidDevice(device)) {
- try {
- return service.getBatteryUsageHint(device);
- } catch (RemoteException e) {
- Log.e(TAG, Log.getStackTraceString(new Throwable()));
- }
- }
- if (service == null) Log.w(TAG, "Proxy not attached to service");
- return -1;
- }
-
- /**
* Indicates if current platform supports voice dialing over bluetooth SCO.
*
* @return true if voice dialing over bluetooth is supported, false otherwise.
@@ -716,49 +689,6 @@
}
/**
- * Accept the incoming connection.
- * Note: This is an internal function and shouldn't be exposed
- *
- * @hide
- */
- public boolean acceptIncomingConnect(BluetoothDevice device) {
- if (DBG) log("acceptIncomingConnect");
- final IBluetoothHeadset service = mService;
- if (service != null && isEnabled()) {
- try {
- return service.acceptIncomingConnect(device);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- }
- return false;
- }
-
- /**
- * Reject the incoming connection.
- *
- * @hide
- */
- public boolean rejectIncomingConnect(BluetoothDevice device) {
- if (DBG) log("rejectIncomingConnect");
- final IBluetoothHeadset service = mService;
- if (service != null) {
- try {
- return service.rejectIncomingConnect(device);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- }
- return false;
- }
-
- /**
* Get the current audio state of the Headset.
* Note: This is an internal function and shouldn't be exposed
*
@@ -1053,50 +983,6 @@
}
/**
- * enable WBS codec setting.
- *
- * @return true if successful false if there was some error such as there is no connected
- * headset
- * @hide
- */
- public boolean enableWBS() {
- final IBluetoothHeadset service = mService;
- if (service != null && isEnabled()) {
- try {
- return service.enableWBS();
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- }
- return false;
- }
-
- /**
- * disable WBS codec settting. It set NBS codec.
- *
- * @return true if successful false if there was some error such as there is no connected
- * headset
- * @hide
- */
- public boolean disableWBS() {
- final IBluetoothHeadset service = mService;
- if (service != null && isEnabled()) {
- try {
- return service.disableWBS();
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- }
- return false;
- }
-
- /**
* check if in-band ringing is supported for this platform.
*
* @return true if in-band ringing is supported false if in-band ringing is not supported
@@ -1107,30 +993,6 @@
com.android.internal.R.bool.config_bluetooth_hfp_inband_ringing_support);
}
- /**
- * Send Headset the BIND response from AG to report change in the status of the
- * HF indicators to the headset
- *
- * @param indId Assigned Number of the indicator (defined by SIG)
- * @param indStatus possible values- false-Indicator is disabled, no value changes shall be
- * sent for this indicator true-Indicator is enabled, value changes may be sent for this
- * indicator
- * @hide
- */
- public void bindResponse(int indId, boolean indStatus) {
- final IBluetoothHeadset service = mService;
- if (service != null && isEnabled()) {
- try {
- service.bindResponse(indId, indStatus);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- }
- }
-
private final IBluetoothProfileServiceConnection mConnection =
new IBluetoothProfileServiceConnection.Stub() {
@Override
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index 6692e13..4a00486 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -31,36 +31,33 @@
import java.util.List;
/**
- * Provides the public APIs to control the Bluetooth HID Device
- * profile.
+ * Provides the public APIs to control the Bluetooth HID Device profile.
*
- * BluetoothHidDevice is a proxy object for controlling the Bluetooth HID
- * Device Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothHidDevice proxy object.
+ * <p>BluetoothHidDevice is a proxy object for controlling the Bluetooth HID Device Service via IPC.
+ * Use {@link BluetoothAdapter#getProfileProxy} to get the BluetoothHidDevice proxy object.
*
- * {@hide}
+ * <p>{@hide}
*/
public final class BluetoothHidDevice implements BluetoothProfile {
private static final String TAG = BluetoothHidDevice.class.getSimpleName();
/**
- * Intent used to broadcast the change in connection state of the Input
- * Host profile.
+ * Intent used to broadcast the change in connection state of the Input Host profile.
*
* <p>This intent will have 3 extras:
+ *
* <ul>
- * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
- * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * <li>{@link #EXTRA_STATE} - The current state of the profile.
+ * <li>{@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
+ * <li>{@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
* </ul>
*
- * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
- * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
- * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of {@link
+ * #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, {@link #STATE_CONNECTED}, {@link
+ * #STATE_DISCONNECTING}.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to receive.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CONNECTION_STATE_CHANGED =
@@ -69,9 +66,8 @@
/**
* Constants representing device subclass.
*
- * @see #registerApp
- * (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)
+ * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+ * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)
*/
public static final byte SUBCLASS1_NONE = (byte) 0x00;
public static final byte SUBCLASS1_KEYBOARD = (byte) 0x40;
@@ -110,8 +106,8 @@
public static final byte ERROR_RSP_UNKNOWN = (byte) 14;
/**
- * Constants representing protocol mode used set by host. Default is always
- * {@link #PROTOCOL_REPORT_MODE} unless notified otherwise.
+ * Constants representing protocol mode used set by host. Default is always {@link
+ * #PROTOCOL_REPORT_MODE} unless notified otherwise.
*
* @see BluetoothHidDeviceCallback#onSetProtocol(BluetoothDevice, byte)
*/
@@ -126,8 +122,8 @@
private BluetoothAdapter mAdapter;
- private static class BluetoothHidDeviceCallbackWrapper extends
- IBluetoothHidDeviceCallback.Stub {
+ private static class BluetoothHidDeviceCallbackWrapper
+ extends IBluetoothHidDeviceCallback.Stub {
private BluetoothHidDeviceCallback mCallback;
@@ -136,9 +132,8 @@
}
@Override
- public void onAppStatusChanged(BluetoothDevice pluggedDevice,
- BluetoothHidDeviceAppConfiguration config, boolean registered) {
- mCallback.onAppStatusChanged(pluggedDevice, config, registered);
+ public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) {
+ mCallback.onAppStatusChanged(pluggedDevice, registered);
}
@Override
@@ -185,13 +180,11 @@
doBind();
}
} catch (IllegalStateException e) {
- Log.e(TAG,
- "onBluetoothStateChange: could not bind to HID Dev "
- + "service: ", e);
+ Log.e(TAG, "onBluetoothStateChange: could not bind to HID Dev "
+ + "service: ", e);
} catch (SecurityException e) {
- Log.e(TAG,
- "onBluetoothStateChange: could not bind to HID Dev "
- + "service: ", e);
+ Log.e(TAG, "onBluetoothStateChange: could not bind to HID Dev "
+ + "service: ", e);
}
} else {
Log.d(TAG, "Unbinding service...");
@@ -201,23 +194,25 @@
}
};
- private final ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- Log.d(TAG, "onServiceConnected()");
- mService = IBluetoothHidDevice.Stub.asInterface(service);
- if (mServiceListener != null) {
- mServiceListener.onServiceConnected(BluetoothProfile.HID_DEVICE,
- BluetoothHidDevice.this);
- }
- }
- public void onServiceDisconnected(ComponentName className) {
- Log.d(TAG, "onServiceDisconnected()");
- mService = null;
- if (mServiceListener != null) {
- mServiceListener.onServiceDisconnected(BluetoothProfile.HID_DEVICE);
- }
- }
- };
+ private final ServiceConnection mConnection =
+ new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ Log.d(TAG, "onServiceConnected()");
+ mService = IBluetoothHidDevice.Stub.asInterface(service);
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(
+ BluetoothProfile.HID_DEVICE, BluetoothHidDevice.this);
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ Log.d(TAG, "onServiceDisconnected()");
+ mService = null;
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.HID_DEVICE);
+ }
+ }
+ };
BluetoothHidDevice(Context context, ServiceListener listener) {
Log.v(TAG, "BluetoothHidDevice");
@@ -281,9 +276,7 @@
mServiceListener = null;
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public List<BluetoothDevice> getConnectedDevices() {
Log.v(TAG, "getConnectedDevices()");
@@ -302,9 +295,7 @@
return new ArrayList<BluetoothDevice>();
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Log.v(TAG, "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states));
@@ -323,9 +314,7 @@
return new ArrayList<BluetoothDevice>();
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public int getConnectionState(BluetoothDevice device) {
Log.v(TAG, "getConnectionState(): device=" + device);
@@ -345,33 +334,31 @@
}
/**
- * Registers application to be used for HID device. Connections to HID
- * Device are only possible when application is registered. Only one
- * application can be registered at time. When no longer used, application
- * should be unregistered using
- * {@link #unregisterApp(BluetoothHidDeviceAppConfiguration)}.
- * The registration status should be tracked by the application by handling callback from
- * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related
- * to the return value of this method.
+ * Registers application to be used for HID device. Connections to HID Device are only possible
+ * when application is registered. Only one application can be registered at one time. When an
+ * application is registered, the HID Host service will be disabled until it is unregistered.
+ * When no longer used, application should be unregistered using {@link #unregisterApp()}. The
+ * registration status should be tracked by the application by handling callback from
+ * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related to
+ * the return value of this method.
*
- * @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of HID Device SDP record.
- * The HID Device SDP record is required.
- * @param inQos {@link BluetoothHidDeviceAppQosSettings} object of Incoming QoS Settings.
- * The Incoming QoS Settings is not required. Use null or default
- * BluetoothHidDeviceAppQosSettings.Builder for default values.
- * @param outQos {@link BluetoothHidDeviceAppQosSettings} object of Outgoing QoS Settings.
- * The Outgoing QoS Settings is not required. Use null or default
- * BluetoothHidDeviceAppQosSettings.Builder for default values.
+ * @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of HID Device SDP record. The HID
+ * Device SDP record is required.
+ * @param inQos {@link BluetoothHidDeviceAppQosSettings} object of Incoming QoS Settings. The
+ * Incoming QoS Settings is not required. Use null or default
+ * BluetoothHidDeviceAppQosSettings.Builder for default values.
+ * @param outQos {@link BluetoothHidDeviceAppQosSettings} object of Outgoing QoS Settings. The
+ * Outgoing QoS Settings is not required. Use null or default
+ * BluetoothHidDeviceAppQosSettings.Builder for default values.
* @param callback {@link BluetoothHidDeviceCallback} object to which callback messages will be
- * sent.
- * The BluetoothHidDeviceCallback object is required.
+ * sent. The BluetoothHidDeviceCallback object is required.
* @return true if the command is successfully sent; otherwise false.
*/
public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp,
BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos,
BluetoothHidDeviceCallback callback) {
Log.v(TAG, "registerApp(): sdp=" + sdp + " inQos=" + inQos + " outQos=" + outQos
- + " callback=" + callback);
+ + " callback=" + callback);
boolean result = false;
@@ -382,11 +369,9 @@
final IBluetoothHidDevice service = mService;
if (service != null) {
try {
- BluetoothHidDeviceAppConfiguration config =
- new BluetoothHidDeviceAppConfiguration();
BluetoothHidDeviceCallbackWrapper cbw =
new BluetoothHidDeviceCallbackWrapper(callback);
- result = service.registerApp(config, sdp, inQos, outQos, cbw);
+ result = service.registerApp(sdp, inQos, outQos, cbw);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -398,22 +383,17 @@
}
/**
- * Unregisters application. Active connection will be disconnected and no
- * new connections will be allowed until registered again using
- * {@link #registerApp
+ * Unregisters application. Active connection will be disconnected and no new connections will
+ * be allowed until registered again using {@link #registerApp
* (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)}
- * The registration status should be tracked by the application by handling callback from
- * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related
- * to the return value of this method.
+ * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)} The registration status should
+ * be tracked by the application by handling callback from
+ * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related to
+ * the return value of this method.
*
- * @param config {@link BluetoothHidDeviceAppConfiguration} object as obtained from {@link
- * BluetoothHidDeviceCallback#onAppStatusChanged(BluetoothDevice,
- * BluetoothHidDeviceAppConfiguration,
- * boolean)}
* @return true if the command is successfully sent; otherwise false.
*/
- public boolean unregisterApp(BluetoothHidDeviceAppConfiguration config) {
+ public boolean unregisterApp() {
Log.v(TAG, "unregisterApp()");
boolean result = false;
@@ -421,7 +401,7 @@
final IBluetoothHidDevice service = mService;
if (service != null) {
try {
- result = service.unregisterApp(config);
+ result = service.unregisterApp();
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -436,7 +416,7 @@
* Sends report to remote host using interrupt channel.
*
* @param id Report Id, as defined in descriptor. Can be 0 in case Report Id are not defined in
- * descriptor.
+ * descriptor.
* @param data Report data, not including Report Id.
* @return true if the command is successfully sent; otherwise false.
*/
@@ -458,8 +438,8 @@
}
/**
- * Sends report to remote host as reply for GET_REPORT request from
- * {@link BluetoothHidDeviceCallback#onGetReport(BluetoothDevice, byte, byte, int)}.
+ * Sends report to remote host as reply for GET_REPORT request from {@link
+ * BluetoothHidDeviceCallback#onGetReport(BluetoothDevice, byte, byte, int)}.
*
* @param type Report Type, as in request.
* @param id Report Id, as in request.
@@ -486,8 +466,8 @@
}
/**
- * Sends error handshake message as reply for invalid SET_REPORT request
- * from {@link BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])}.
+ * Sends error handshake message as reply for invalid SET_REPORT request from {@link
+ * BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])}.
*
* @param error Error to be sent for SET_REPORT via HANDSHAKE.
* @return true if the command is successfully sent; otherwise false.
@@ -515,6 +495,7 @@
* Sends Virtual Cable Unplug to currently connected host.
*
* @return
+ * {@hide}
*/
public boolean unplug(BluetoothDevice device) {
Log.v(TAG, "unplug(): device=" + device);
@@ -536,11 +517,11 @@
}
/**
- * Initiates connection to host which is currently paired with this device.
- * If the application is not registered, #connect(BluetoothDevice) will fail.
- * The connection state should be tracked by the application by handling callback from
- * BluetoothHidDeviceCallback#onConnectionStateChanged. The connection state is not related
- * to the return value of this method.
+ * Initiates connection to host which is currently paired with this device. If the application
+ * is not registered, #connect(BluetoothDevice) will fail. The connection state should be
+ * tracked by the application by handling callback from
+ * BluetoothHidDeviceCallback#onConnectionStateChanged. The connection state is not related to
+ * the return value of this method.
*
* @return true if the command is successfully sent; otherwise false.
*/
@@ -564,10 +545,9 @@
}
/**
- * Disconnects from currently connected host.
- * The connection state should be tracked by the application by handling callback from
- * BluetoothHidDeviceCallback#onConnectionStateChanged. The connection state is not related
- * to the return value of this method.
+ * Disconnects from currently connected host. The connection state should be tracked by the
+ * application by handling callback from BluetoothHidDeviceCallback#onConnectionStateChanged.
+ * The connection state is not related to the return value of this method.
*
* @return true if the command is successfully sent; otherwise false.
*/
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java b/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java
deleted file mode 100644
index d1efa2d..0000000
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2016 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.bluetooth;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Random;
-
-/**
- * Represents the app configuration for a Bluetooth HID Device application.
- *
- * The app needs a BluetoothHidDeviceAppConfiguration token to unregister
- * the Bluetooth HID Device service.
- *
- * {@see BluetoothHidDevice}
- *
- * {@hide}
- */
-public final class BluetoothHidDeviceAppConfiguration implements Parcelable {
- private final long mHash;
-
- BluetoothHidDeviceAppConfiguration() {
- Random rnd = new Random();
- mHash = rnd.nextLong();
- }
-
- BluetoothHidDeviceAppConfiguration(long hash) {
- mHash = hash;
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof BluetoothHidDeviceAppConfiguration) {
- BluetoothHidDeviceAppConfiguration config = (BluetoothHidDeviceAppConfiguration) o;
- return mHash == config.mHash;
- }
- return false;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Parcelable.Creator<BluetoothHidDeviceAppConfiguration> CREATOR =
- new Parcelable.Creator<BluetoothHidDeviceAppConfiguration>() {
-
- @Override
- public BluetoothHidDeviceAppConfiguration createFromParcel(Parcel in) {
- long hash = in.readLong();
- return new BluetoothHidDeviceAppConfiguration(hash);
- }
-
- @Override
- public BluetoothHidDeviceAppConfiguration[] newArray(int size) {
- return new BluetoothHidDeviceAppConfiguration[size];
- }
- };
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeLong(mHash);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
index 881ae98..4609d52 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
@@ -20,15 +20,14 @@
import android.os.Parcelable;
/**
- * Represents the Quality of Service (QoS) settings for a Bluetooth HID Device
- * application.
+ * Represents the Quality of Service (QoS) settings for a Bluetooth HID Device application.
*
- * The BluetoothHidDevice framework will update the L2CAP QoS settings for the
- * app during registration.
+ * <p>The BluetoothHidDevice framework will update the L2CAP QoS settings for the app during
+ * registration.
*
- * {@see BluetoothHidDevice}
+ * <p>{@see BluetoothHidDevice}
*
- * {@hide}
+ * <p>{@hide}
*/
public final class BluetoothHidDeviceAppQosSettings implements Parcelable {
@@ -46,13 +45,12 @@
public static final int MAX = (int) 0xffffffff;
/**
- * Create a BluetoothHidDeviceAppQosSettings object for the Bluetooth L2CAP channel.
- * The QoS Settings is optional.
- * Recommended to use BluetoothHidDeviceAppQosSettings.Builder.
- * {@see <a href="https://www.bluetooth.com/specifications/profiles-overview">
- * https://www.bluetooth.com/specifications/profiles-overview
- * </a>
- * Bluetooth HID Specfication v1.1.1 Section 5.2 and Appendix D }
+ * Create a BluetoothHidDeviceAppQosSettings object for the Bluetooth L2CAP channel. The QoS
+ * Settings is optional. Recommended to use BluetoothHidDeviceAppQosSettings.Builder. {@see <a
+ * href="https://www.bluetooth.com/specifications/profiles-overview">
+ * https://www.bluetooth.com/specifications/profiles-overview </a> Bluetooth HID Specfication
+ * v1.1.1 Section 5.2 and Appendix D }
+ *
* @param serviceType L2CAP service type
* @param tokenRate L2CAP token rate
* @param tokenBucketSize L2CAP token bucket size
@@ -123,13 +121,11 @@
/** @return an int array representation of this instance */
public int[] toArray() {
return new int[] {
- serviceType, tokenRate, tokenBucketSize, peakBandwidth, latency, delayVariation
+ serviceType, tokenRate, tokenBucketSize, peakBandwidth, latency, delayVariation
};
}
- /**
- * A helper to build the BluetoothHidDeviceAppQosSettings object.
- */
+ /** A helper to build the BluetoothHidDeviceAppQosSettings object. */
public static class Builder {
// Optional parameters - initialized to default values
private int mServiceType = SERVICE_BEST_EFFORT;
@@ -141,8 +137,9 @@
/**
* Set the service type.
+ *
* @param val service type. Should be one of {SERVICE_NO_TRAFFIC, SERVICE_BEST_EFFORT,
- * SERVICE_GUARANTEED}, with SERVICE_BEST_EFFORT being the default one.
+ * SERVICE_GUARANTEED}, with SERVICE_BEST_EFFORT being the default one.
* @return BluetoothHidDeviceAppQosSettings Builder with specified service type.
*/
public Builder serviceType(int val) {
@@ -151,6 +148,7 @@
}
/**
* Set the token rate.
+ *
* @param val token rate
* @return BluetoothHidDeviceAppQosSettings Builder with specified token rate.
*/
@@ -161,6 +159,7 @@
/**
* Set the bucket size.
+ *
* @param val bucket size
* @return BluetoothHidDeviceAppQosSettings Builder with specified bucket size.
*/
@@ -171,6 +170,7 @@
/**
* Set the peak bandwidth.
+ *
* @param val peak bandwidth
* @return BluetoothHidDeviceAppQosSettings Builder with specified peak bandwidth.
*/
@@ -180,6 +180,7 @@
}
/**
* Set the latency.
+ *
* @param val latency
* @return BluetoothHidDeviceAppQosSettings Builder with specified latency.
*/
@@ -190,6 +191,7 @@
/**
* Set the delay variation.
+ *
* @param val delay variation
* @return BluetoothHidDeviceAppQosSettings Builder with specified delay variation.
*/
@@ -200,6 +202,7 @@
/**
* Build the BluetoothHidDeviceAppQosSettings object.
+ *
* @return BluetoothHidDeviceAppQosSettings object with current settings.
*/
public BluetoothHidDeviceAppQosSettings build() {
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
index 4669637..2da64e5 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
@@ -22,16 +22,14 @@
import java.util.Arrays;
/**
- * Represents the Service Discovery Protocol (SDP) settings for a Bluetooth
- * HID Device application.
+ * Represents the Service Discovery Protocol (SDP) settings for a Bluetooth HID Device application.
*
- * The BluetoothHidDevice framework adds the SDP record during app
- * registration, so that the Android device can be discovered as a Bluetooth
- * HID Device.
+ * <p>The BluetoothHidDevice framework adds the SDP record during app registration, so that the
+ * Android device can be discovered as a Bluetooth HID Device.
*
- * {@see BluetoothHidDevice}
+ * <p>{@see BluetoothHidDevice}
*
- * {@hide}
+ * <p>{@hide}
*/
public final class BluetoothHidDeviceAppSdpSettings implements Parcelable {
@@ -43,18 +41,19 @@
/**
* Create a BluetoothHidDeviceAppSdpSettings object for the Bluetooth SDP record.
+ *
* @param name Name of this Bluetooth HID device. Maximum length is 50 bytes.
* @param description Description for this Bluetooth HID device. Maximum length is 50 bytes.
* @param provider Provider of this Bluetooth HID device. Maximum length is 50 bytes.
- * @param subclass Subclass of this Bluetooth HID device.
- * See <a href="www.usb.org/developers/hidpage/HID1_11.pdf">
+ * @param subclass Subclass of this Bluetooth HID device. See <a
+ * href="www.usb.org/developers/hidpage/HID1_11.pdf">
* www.usb.org/developers/hidpage/HID1_11.pdf Section 4.2</a>
- * @param descriptors Descriptors of this Bluetooth HID device.
- * See <a href="www.usb.org/developers/hidpage/HID1_11.pdf">
+ * @param descriptors Descriptors of this Bluetooth HID device. See <a
+ * href="www.usb.org/developers/hidpage/HID1_11.pdf">
* www.usb.org/developers/hidpage/HID1_11.pdf Chapter 6</a> Maximum length is 2048 bytes.
*/
- public BluetoothHidDeviceAppSdpSettings(String name, String description, String provider,
- byte subclass, byte[] descriptors) {
+ public BluetoothHidDeviceAppSdpSettings(
+ String name, String description, String provider, byte subclass, byte[] descriptors) {
this.name = name;
this.description = description;
this.provider = provider;
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
index 5ccda0d..6ed1965 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
@@ -19,50 +19,43 @@
import android.util.Log;
/**
- * The template class that applications use to call callback functions on
- * events from the HID host. Callback functions are wrapped in this class and
- * registered to the Android system during app registration.
+ * The template class that applications use to call callback functions on events from the HID host.
+ * Callback functions are wrapped in this class and registered to the Android system during app
+ * registration.
*
- * {@see BluetoothHidDevice}
+ * <p>{@see BluetoothHidDevice}
*
- * {@hide}
+ * <p>{@hide}
*/
public abstract class BluetoothHidDeviceCallback {
private static final String TAG = "BluetoothHidDevCallback";
/**
- * Callback called when application registration state changes. Usually it's
- * called due to either
- * {@link BluetoothHidDevice#registerApp
- * (String, String, String, byte, byte[], BluetoothHidDeviceCallback)}
- * or
- * {@link BluetoothHidDevice#unregisterApp(BluetoothHidDeviceAppConfiguration)}
- * , but can be also unsolicited in case e.g. Bluetooth was turned off in
- * which case application is unregistered automatically.
+ * Callback called when application registration state changes. Usually it's called due to
+ * either {@link BluetoothHidDevice#registerApp (String, String, String, byte, byte[],
+ * BluetoothHidDeviceCallback)} or {@link BluetoothHidDevice#unregisterApp()} , but can be also
+ * unsolicited in case e.g. Bluetooth was turned off in which case application is unregistered
+ * automatically.
*
* @param pluggedDevice {@link BluetoothDevice} object which represents host that currently has
- * Virtual Cable established with device. Only valid when application is registered, can be
- * <code>null</code>.
- * @param config {@link BluetoothHidDeviceAppConfiguration} object which represents token
- * required to unregister application using
- * {@link BluetoothHidDevice#unregisterApp(BluetoothHidDeviceAppConfiguration)}.
+ * Virtual Cable established with device. Only valid when application is registered, can be
+ * <code>null</code>.
* @param registered <code>true</code> if application is registered, <code>false</code>
- * otherwise.
+ * otherwise.
*/
- public void onAppStatusChanged(BluetoothDevice pluggedDevice,
- BluetoothHidDeviceAppConfiguration config, boolean registered) {
- Log.d(TAG, "onAppStatusChanged: pluggedDevice=" + pluggedDevice + " registered="
- + registered);
+ public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) {
+ Log.d(TAG,
+ "onAppStatusChanged: pluggedDevice=" + pluggedDevice + " registered=" + registered);
}
/**
- * Callback called when connection state with remote host was changed.
- * Application can assume than Virtual Cable is established when called with
- * {@link BluetoothProfile#STATE_CONNECTED} <code>state</code>.
+ * Callback called when connection state with remote host was changed. Application can assume
+ * than Virtual Cable is established when called with {@link BluetoothProfile#STATE_CONNECTED}
+ * <code>state</code>.
*
* @param device {@link BluetoothDevice} object representing host device which connection state
- * was changed.
+ * was changed.
* @param state Connection state as defined in {@link BluetoothProfile}.
*/
public void onConnectionStateChanged(BluetoothDevice device, int state) {
@@ -70,14 +63,14 @@
}
/**
- * Callback called when GET_REPORT is received from remote host. Should be
- * replied by application using
- * {@link BluetoothHidDevice#replyReport(BluetoothDevice, byte, byte, byte[])}.
+ * Callback called when GET_REPORT is received from remote host. Should be replied by
+ * application using {@link BluetoothHidDevice#replyReport(BluetoothDevice, byte, byte,
+ * byte[])}.
*
* @param type Requested Report Type.
* @param id Requested Report Id, can be 0 if no Report Id are defined in descriptor.
* @param bufferSize Requested buffer size, application shall respond with at least given number
- * of bytes.
+ * of bytes.
*/
public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) {
Log.d(TAG, "onGetReport: device=" + device + " type=" + type + " id=" + id + " bufferSize="
@@ -85,9 +78,9 @@
}
/**
- * Callback called when SET_REPORT is received from remote host. In case
- * received data are invalid, application shall respond with
- * {@link BluetoothHidDevice#reportError(BluetoothDevice, byte)}.
+ * Callback called when SET_REPORT is received from remote host. In case received data are
+ * invalid, application shall respond with {@link
+ * BluetoothHidDevice#reportError(BluetoothDevice, byte)}.
*
* @param type Report Type.
* @param id Report Id.
@@ -98,10 +91,9 @@
}
/**
- * Callback called when SET_PROTOCOL is received from remote host.
- * Application shall use this information to send only reports valid for
- * given protocol mode. By default,
- * {@link BluetoothHidDevice#PROTOCOL_REPORT_MODE} shall be assumed.
+ * Callback called when SET_PROTOCOL is received from remote host. Application shall use this
+ * information to send only reports valid for given protocol mode. By default, {@link
+ * BluetoothHidDevice#PROTOCOL_REPORT_MODE} shall be assumed.
*
* @param protocol Protocol Mode.
*/
@@ -110,9 +102,8 @@
}
/**
- * Callback called when report data is received over interrupt channel.
- * Report Type is assumed to be
- * {@link BluetoothHidDevice#REPORT_TYPE_OUTPUT}.
+ * Callback called when report data is received over interrupt channel. Report Type is assumed
+ * to be {@link BluetoothHidDevice#REPORT_TYPE_OUTPUT}.
*
* @param reportId Report Id.
* @param data Report data.
@@ -122,10 +113,8 @@
}
/**
- * Callback called when Virtual Cable is removed. This can be either due to
- * {@link BluetoothHidDevice#unplug(BluetoothDevice)} or request from remote
- * side. After this callback is received connection will be disconnected
- * automatically.
+ * Callback called when Virtual Cable is removed. After this callback is
+ * received connection will be disconnected automatically.
*/
public void onVirtualCableUnplug(BluetoothDevice device) {
Log.d(TAG, "onVirtualCableUnplug: device=" + device);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 19e24ad..9800ab0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -754,6 +754,8 @@
* to any callers for the same name, meaning they will see each other's
* edits as soon as they are made.
*
+ * This method is thead-safe.
+ *
* @param name Desired preferences file. If a preferences file by this name
* does not exist, it will be created when you retrieve an
* editor (SharedPreferences.edit()) and then commit changes (Editor.commit()).
@@ -2799,10 +2801,17 @@
* example, if this Context is an Activity that is stopped, the service will
* not be required to continue running until the Activity is resumed.
*
- * <p>This function will throw {@link SecurityException} if you do not
+ * <p>If the service does not support binding, it may return {@code null} from
+ * its {@link android.app.Service#onBind(Intent) onBind()} method. If it does, then
+ * the ServiceConnection's
+ * {@link ServiceConnection#onNullBinding(ComponentName) onNullBinding()} method
+ * will be invoked instead of
+ * {@link ServiceConnection#onServiceConnected(ComponentName, IBinder) onServiceConnected()}.
+ *
+ * <p>This method will throw {@link SecurityException} if the calling app does not
* have permission to bind to the given service.
*
- * <p class="note">Note: this method <em>can not be called from a
+ * <p class="note">Note: this method <em>cannot be called from a
* {@link BroadcastReceiver} component</em>. A pattern you can use to
* communicate from a BroadcastReceiver to a Service is to call
* {@link #startService} with the arguments containing the command to be
@@ -2825,8 +2834,8 @@
* {@link #BIND_WAIVE_PRIORITY}.
* @return If you have successfully bound to the service, {@code true} is returned;
* {@code false} is returned if the connection is not made so you will not
- * receive the service object. However, you should still call
- * {@link #unbindService} to release the connection.
+ * receive the service object. You should still call {@link #unbindService}
+ * to release the connection even if this method returned {@code false}.
*
* @throws SecurityException If the caller does not have permission to access the service
* or the service can not be found.
@@ -3404,6 +3413,14 @@
public static final String NETWORKMANAGEMENT_SERVICE = "network_management";
/**
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link com.android.server.slice.SliceManagerService} for managing slices.
+ * @hide
+ * @see #getSystemService
+ */
+ public static final String SLICE_SERVICE = "slice";
+
+ /**
* Use with {@link #getSystemService} to retrieve a {@link
* android.app.usage.NetworkStatsManager} for querying network usage stats.
*
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index bad452c..6fb1afd 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4455,10 +4455,34 @@
public static final String EXTRA_EPHEMERAL_TOKEN = "android.intent.extra.EPHEMERAL_TOKEN";
/**
+ * The action that triggered an instant application resolution.
+ * @hide
+ */
+ public static final String EXTRA_INSTANT_APP_ACTION = "android.intent.extra.INSTANT_APP_ACTION";
+
+ /**
+ * A {@link Bundle} of metadata that describes the instanta application that needs to be
+ * installed. This data is populated from the response to
+ * {@link android.content.pm.InstantAppResolveInfo#getExtras()} as provided by the registered
+ * instant application resolver.
+ * @hide
+ */
+ public static final String EXTRA_INSTANT_APP_EXTRAS =
+ "android.intent.extra.INSTANT_APP_EXTRAS";
+
+ /**
+ * The version code of the app to install components from.
+ * @deprecated Use {@link #EXTRA_LONG_VERSION_CODE).
+ * @hide
+ */
+ @Deprecated
+ public static final String EXTRA_VERSION_CODE = "android.intent.extra.VERSION_CODE";
+
+ /**
* The version code of the app to install components from.
* @hide
*/
- public static final String EXTRA_VERSION_CODE = "android.intent.extra.VERSION_CODE";
+ public static final String EXTRA_LONG_VERSION_CODE = "android.intent.extra.LONG_VERSION_CODE";
/**
* The app that triggered the ephemeral installation.
@@ -4891,8 +4915,9 @@
* <li>Enumeration of features here is not meant to restrict capabilities of the quick viewer.
* Quick viewer can implement features not listed below.
* <li>Features included at this time are: {@link QuickViewConstants#FEATURE_VIEW},
- * {@link QuickViewConstants#FEATURE_EDIT}, {@link QuickViewConstants#FEATURE_DOWNLOAD},
- * {@link QuickViewConstants#FEATURE_SEND}, {@link QuickViewConstants#FEATURE_PRINT}.
+ * {@link QuickViewConstants#FEATURE_EDIT}, {@link QuickViewConstants#FEATURE_DELETE},
+ * {@link QuickViewConstants#FEATURE_DOWNLOAD}, {@link QuickViewConstants#FEATURE_SEND},
+ * {@link QuickViewConstants#FEATURE_PRINT}.
* <p>
* Requirements:
* <li>Quick viewer shouldn't show a feature if the feature is absent in
diff --git a/core/java/android/content/QuickViewConstants.java b/core/java/android/content/QuickViewConstants.java
index 7455d0c..a25513d 100644
--- a/core/java/android/content/QuickViewConstants.java
+++ b/core/java/android/content/QuickViewConstants.java
@@ -33,7 +33,7 @@
public static final String FEATURE_VIEW = "android:view";
/**
- * Feature to view a document using system standard editing mechanism, like
+ * Feature to edit a document using system standard editing mechanism, like
* {@link Intent#ACTION_EDIT}.
*
* @see Intent#EXTRA_QUICK_VIEW_FEATURES
@@ -42,6 +42,15 @@
public static final String FEATURE_EDIT = "android:edit";
/**
+ * Feature to delete an individual document. Quick viewer implementations must use
+ * Storage Access Framework to both verify delete permission and to delete content.
+ *
+ * @see DocumentsContract#Document#FLAG_SUPPORTS_DELETE
+ * @see DocumentsContract#deleteDocument(ContentResolver resolver, Uri documentUri)
+ */
+ public static final String FEATURE_DELETE = "android:delete";
+
+ /**
* Feature to view a document using system standard sending mechanism, like
* {@link Intent#ACTION_SEND}.
*
diff --git a/core/java/android/content/ServiceConnection.java b/core/java/android/content/ServiceConnection.java
index 6ff4900..c16dbbe 100644
--- a/core/java/android/content/ServiceConnection.java
+++ b/core/java/android/content/ServiceConnection.java
@@ -63,4 +63,21 @@
*/
default void onBindingDied(ComponentName name) {
}
+
+ /**
+ * Called when the service being bound has returned {@code null} from its
+ * {@link android.app.Service#onBind(Intent) onBind()} method. This indicates
+ * that the attempting service binding represented by this ServiceConnection
+ * will never become usable.
+ *
+ * <p class="note">The app which requested the binding must still call
+ * {@link Context#unbindService(ServiceConnection)} to release the tracking
+ * resources associated with this ServiceConnection even if this callback was
+ * invoked following {@link Context#bindService Context.bindService() bindService()}.
+ *
+ * @param name The concrete component name of the service whose binding
+ * has been rejected by the Service implementation.
+ */
+ default void onNullBinding(ComponentName name) {
+ }
}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 837c00a..f8cdce6 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1156,6 +1156,7 @@
dest.writeString(permission);
dest.writeString(taskAffinity);
dest.writeString(targetActivity);
+ dest.writeString(launchToken);
dest.writeInt(flags);
dest.writeInt(screenOrientation);
dest.writeInt(configChanges);
@@ -1282,6 +1283,7 @@
permission = source.readString();
taskAffinity = source.readString();
targetActivity = source.readString();
+ launchToken = source.readString();
flags = source.readInt();
screenOrientation = source.readInt();
configChanges = source.readInt();
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index edb27cd..84b1ff3 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -594,6 +594,13 @@
*/
public static final int PRIVATE_FLAG_OEM = 1 << 17;
+ /**
+ * Value for {@linl #privateFlags}: whether this app is pre-installed on the
+ * vendor partition of the system image.
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_VENDOR = 1 << 18;
+
/** @hide */
@IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = {
PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE,
@@ -613,6 +620,7 @@
PRIVATE_FLAG_PRIVILEGED,
PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER,
PRIVATE_FLAG_STATIC_SHARED_LIBRARY,
+ PRIVATE_FLAG_VENDOR,
PRIVATE_FLAG_VIRTUAL_PRELOAD,
})
@Retention(RetentionPolicy.SOURCE)
@@ -888,7 +896,7 @@
* The app's declared version code.
* @hide
*/
- public int versionCode;
+ public long versionCode;
/**
* The user-visible SDK version (ex. 26) of the framework against which the application claims
@@ -1315,7 +1323,7 @@
dest.writeInt(uid);
dest.writeInt(minSdkVersion);
dest.writeInt(targetSdkVersion);
- dest.writeInt(versionCode);
+ dest.writeLong(versionCode);
dest.writeInt(enabled ? 1 : 0);
dest.writeInt(enabledSetting);
dest.writeInt(installLocation);
@@ -1384,7 +1392,7 @@
uid = source.readInt();
minSdkVersion = source.readInt();
targetSdkVersion = source.readInt();
- versionCode = source.readInt();
+ versionCode = source.readLong();
enabled = source.readInt() != 0;
enabledSetting = source.readInt();
installLocation = source.readInt();
@@ -1569,6 +1577,11 @@
return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
}
+ /** @hide */
+ public boolean isVendor() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
+ }
+
/**
* Returns whether or not this application was installed as a virtual preload.
*/
diff --git a/core/java/android/content/pm/AuxiliaryResolveInfo.java b/core/java/android/content/pm/AuxiliaryResolveInfo.java
index 067363d..6bdcefb 100644
--- a/core/java/android/content/pm/AuxiliaryResolveInfo.java
+++ b/core/java/android/content/pm/AuxiliaryResolveInfo.java
@@ -45,7 +45,7 @@
/** Opaque token to track the instant application resolution */
public final String token;
/** The version code of the package */
- public final int versionCode;
+ public final long versionCode;
/** An intent to start upon failure to install */
public final Intent failureIntent;
@@ -71,7 +71,7 @@
public AuxiliaryResolveInfo(@NonNull String packageName,
@Nullable String splitName,
@Nullable ComponentName failureActivity,
- int versionCode,
+ long versionCode,
@Nullable Intent failureIntent) {
super();
this.packageName = packageName;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 64d33d5..56a0def 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -48,6 +48,7 @@
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VersionedPackage;
+import android.content.pm.dex.IArtManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
@@ -657,4 +658,6 @@
ComponentName getInstantAppInstallerComponent();
String getInstantAppAndroidId(String packageName, int userId);
+
+ IArtManager getArtManager();
}
diff --git a/core/java/android/content/pm/InstantAppInfo.java b/core/java/android/content/pm/InstantAppInfo.java
index 67afc92..cb04fc3 100644
--- a/core/java/android/content/pm/InstantAppInfo.java
+++ b/core/java/android/content/pm/InstantAppInfo.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -31,6 +32,7 @@
*
* @hide
*/
+@SystemApi
public final class InstantAppInfo implements Parcelable {
private final ApplicationInfo mApplicationInfo;
diff --git a/core/java/android/content/pm/InstantAppResolveInfo.java b/core/java/android/content/pm/InstantAppResolveInfo.java
index 22e994f..19cb932 100644
--- a/core/java/android/content/pm/InstantAppResolveInfo.java
+++ b/core/java/android/content/pm/InstantAppResolveInfo.java
@@ -19,8 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.content.IntentFilter;
-import android.net.Uri;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -44,10 +43,18 @@
/** The filters used to match domain */
private final List<InstantAppIntentFilter> mFilters;
/** The version code of the app that this class resolves to */
- private final int mVersionCode;
+ private final long mVersionCode;
+ /** Data about the app that should be passed along to the Instant App installer on resolve */
+ private final Bundle mExtras;
public InstantAppResolveInfo(@NonNull InstantAppDigest digest, @Nullable String packageName,
@Nullable List<InstantAppIntentFilter> filters, int versionCode) {
+ this(digest, packageName, filters, (long) versionCode, null /* extras */);
+ }
+
+ public InstantAppResolveInfo(@NonNull InstantAppDigest digest, @Nullable String packageName,
+ @Nullable List<InstantAppIntentFilter> filters, long versionCode,
+ @Nullable Bundle extras) {
// validate arguments
if ((packageName == null && (filters != null && filters.size() != 0))
|| (packageName != null && (filters == null || filters.size() == 0))) {
@@ -62,11 +69,13 @@
}
mPackageName = packageName;
mVersionCode = versionCode;
+ mExtras = extras;
}
public InstantAppResolveInfo(@NonNull String hostName, @Nullable String packageName,
@Nullable List<InstantAppIntentFilter> filters) {
- this(new InstantAppDigest(hostName), packageName, filters, -1 /*versionCode*/);
+ this(new InstantAppDigest(hostName), packageName, filters, -1 /*versionCode*/,
+ null /* extras */);
}
InstantAppResolveInfo(Parcel in) {
@@ -74,7 +83,8 @@
mPackageName = in.readString();
mFilters = new ArrayList<InstantAppIntentFilter>();
in.readList(mFilters, null /*loader*/);
- mVersionCode = in.readInt();
+ mVersionCode = in.readLong();
+ mExtras = in.readBundle();
}
public byte[] getDigestBytes() {
@@ -93,10 +103,23 @@
return mFilters;
}
+ /**
+ * @deprecated Use {@link #getLongVersionCode} instead.
+ */
+ @Deprecated
public int getVersionCode() {
+ return (int) (mVersionCode & 0xffffffff);
+ }
+
+ public long getLongVersionCode() {
return mVersionCode;
}
+ @Nullable
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -107,7 +130,8 @@
out.writeParcelable(mDigest, flags);
out.writeString(mPackageName);
out.writeList(mFilters);
- out.writeInt(mVersionCode);
+ out.writeLong(mVersionCode);
+ out.writeBundle(mExtras);
}
public static final Parcelable.Creator<InstantAppResolveInfo> CREATOR
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 9e54e23..d09ba0b 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -265,6 +265,14 @@
/**
* Include pinned shortcuts in the result.
+ *
+ * <p>If you are the selected assistant app, and wishes to fetch all shortcuts that the
+ * user owns on the launcher (or by other launchers, in case the user has multiple), use
+ * {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} instead.
+ *
+ * <p>If you're a regular launcher app, there's no way to get shortcuts pinned by other
+ * launchers, and {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} will be ignored. So use this
+ * flag to get own pinned shortcuts.
*/
public static final int FLAG_MATCH_PINNED = 1 << 1;
@@ -285,8 +293,15 @@
* Include all pinned shortcuts by any launchers, not just by the caller,
* in the result.
*
- * The caller must be the selected assistant app to use this flag, or have the system
+ * <p>The caller must be the selected assistant app to use this flag, or have the system
* {@code ACCESS_SHORTCUTS} permission.
+ *
+ * <p>If you are the selected assistant app, and wishes to fetch all shortcuts that the
+ * user owns on the launcher (or by other launchers, in case the user has multiple), use
+ * {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} instead.
+ *
+ * <p>If you're a regular launcher app (or any app that's not the selected assistant app)
+ * then this flag will be ignored.
*/
public static final int FLAG_MATCH_PINNED_BY_ANY_LAUNCHER = 1 << 10;
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index f8889b6..0c893b0 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -37,13 +37,56 @@
public String[] splitNames;
/**
+ * @deprecated Use {@link #getLongVersionCode()} instead, which includes both
+ * this and the additional
+ * {@link android.R.styleable#AndroidManifest_versionCodeMajor versionCodeMajor} attribute.
* The version number of this package, as specified by the <manifest>
* tag's {@link android.R.styleable#AndroidManifest_versionCode versionCode}
* attribute.
+ * @see #getLongVersionCode()
*/
+ @Deprecated
public int versionCode;
/**
+ * @hide
+ * The major version number of this package, as specified by the <manifest>
+ * tag's {@link android.R.styleable#AndroidManifest_versionCode versionCodeMajor}
+ * attribute.
+ * @see #getLongVersionCode()
+ */
+ public int versionCodeMajor;
+
+ /**
+ * Return {@link android.R.styleable#AndroidManifest_versionCode versionCode} and
+ * {@link android.R.styleable#AndroidManifest_versionCodeMajor versionCodeMajor} combined
+ * together as a single long value. The
+ * {@link android.R.styleable#AndroidManifest_versionCodeMajor versionCodeMajor} is placed in
+ * the upper 32 bits.
+ */
+ public long getLongVersionCode() {
+ return composeLongVersionCode(versionCodeMajor, versionCode);
+ }
+
+ /**
+ * Set the full version code in this PackageInfo, updating {@link #versionCode}
+ * with the lower bits.
+ * @see #getLongVersionCode()
+ */
+ public void setLongVersionCode(long longVersionCode) {
+ versionCodeMajor = (int) (longVersionCode>>32);
+ versionCode = (int) longVersionCode;
+ }
+
+ /**
+ * @hide Internal implementation for composing a minor and major version code in to
+ * a single long version code.
+ */
+ public static long composeLongVersionCode(int major, int minor) {
+ return (((long) major) << 32) | (((long) minor) & 0xffffffffL);
+ }
+
+ /**
* The version name of this package, as specified by the <manifest>
* tag's {@link android.R.styleable#AndroidManifest_versionName versionName}
* attribute.
@@ -333,6 +376,7 @@
dest.writeString(packageName);
dest.writeStringArray(splitNames);
dest.writeInt(versionCode);
+ dest.writeInt(versionCodeMajor);
dest.writeString(versionName);
dest.writeInt(baseRevisionCode);
dest.writeIntArray(splitRevisionCodes);
@@ -389,6 +433,7 @@
packageName = source.readString();
splitNames = source.createStringArray();
versionCode = source.readInt();
+ versionCodeMajor = source.readInt();
versionName = source.readString();
baseRevisionCode = source.readInt();
splitRevisionCodes = source.createIntArray();
diff --git a/core/java/android/content/pm/PackageInfoLite.java b/core/java/android/content/pm/PackageInfoLite.java
index 1efe082..bbf020d 100644
--- a/core/java/android/content/pm/PackageInfoLite.java
+++ b/core/java/android/content/pm/PackageInfoLite.java
@@ -38,9 +38,27 @@
/**
* The android:versionCode of the package.
+ * @deprecated Use {@link #getLongVersionCode()} instead, which includes both
+ * this and the additional
+ * {@link android.R.styleable#AndroidManifest_versionCode versionCodeMajor} attribute.
*/
+ @Deprecated
public int versionCode;
+ /**
+ * @hide
+ * The android:versionCodeMajor of the package.
+ */
+ public int versionCodeMajor;
+
+ /**
+ * Return {@link #versionCode} and {@link #versionCodeMajor} combined together as a
+ * single long value. The {@link #versionCodeMajor} is placed in the upper 32 bits.
+ */
+ public long getLongVersionCode() {
+ return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode);
+ }
+
/** Revision code of base APK */
public int baseRevisionCode;
/** Revision codes of any split APKs, ordered by parsed splitName */
@@ -55,10 +73,10 @@
/**
* Specifies the recommended install location. Can be one of
- * {@link #PackageHelper.RECOMMEND_INSTALL_INTERNAL} to install on internal storage
- * {@link #PackageHelper.RECOMMEND_INSTALL_EXTERNAL} to install on external media
- * {@link PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE} for storage errors
- * {@link PackageHelper.RECOMMEND_FAILED_INVALID_APK} for parse errors.
+ * {@link PackageHelper#RECOMMEND_INSTALL_INTERNAL} to install on internal storage,
+ * {@link PackageHelper#RECOMMEND_INSTALL_EXTERNAL} to install on external media,
+ * {@link PackageHelper#RECOMMEND_FAILED_INSUFFICIENT_STORAGE} for storage errors,
+ * or {@link PackageHelper#RECOMMEND_FAILED_INVALID_APK} for parse errors.
*/
public int recommendedInstallLocation;
public int installLocation;
@@ -82,6 +100,7 @@
dest.writeString(packageName);
dest.writeStringArray(splitNames);
dest.writeInt(versionCode);
+ dest.writeInt(versionCodeMajor);
dest.writeInt(baseRevisionCode);
dest.writeIntArray(splitRevisionCodes);
dest.writeInt(recommendedInstallLocation);
@@ -111,6 +130,7 @@
packageName = source.readString();
splitNames = source.createStringArray();
versionCode = source.readInt();
+ versionCodeMajor = source.readInt();
baseRevisionCode = source.readInt();
splitRevisionCodes = source.createIntArray();
recommendedInstallLocation = source.readInt();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f796aab..ff02c40 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -42,6 +42,7 @@
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.dex.ArtManager;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.Rect;
@@ -2634,11 +2635,20 @@
/**
* Extra field name for the version code of a package pending verification.
+ * @deprecated Use {@link #EXTRA_VERIFICATION_LONG_VERSION_CODE} instead.
+ * @hide
+ */
+ @Deprecated
+ public static final String EXTRA_VERIFICATION_VERSION_CODE
+ = "android.content.pm.extra.VERIFICATION_VERSION_CODE";
+
+ /**
+ * Extra field name for the long version code of a package pending verification.
*
* @hide
*/
- public static final String EXTRA_VERIFICATION_VERSION_CODE
- = "android.content.pm.extra.VERIFICATION_VERSION_CODE";
+ public static final String EXTRA_VERIFICATION_LONG_VERSION_CODE =
+ "android.content.pm.extra.VERIFICATION_LONG_VERSION_CODE";
/**
* Extra field name for the ID of a intent filter pending verification.
@@ -5842,4 +5852,14 @@
@SystemApi
public abstract void registerDexModule(String dexModulePath,
@Nullable DexModuleRegisterCallback callback);
+
+ /**
+ * Returns the {@link ArtManager} associated with this package manager.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @NonNull ArtManager getArtManager() {
+ throw new UnsupportedOperationException("getArtManager not implemented in subclass");
+ }
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 68bb562..153c944 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -394,6 +394,7 @@
public static class PackageLite {
public final String packageName;
public final int versionCode;
+ public final int versionCodeMajor;
public final int installLocation;
public final VerifierInfo[] verifiers;
@@ -436,6 +437,7 @@
String[] splitCodePaths, int[] splitRevisionCodes) {
this.packageName = baseApk.packageName;
this.versionCode = baseApk.versionCode;
+ this.versionCodeMajor = baseApk.versionCodeMajor;
this.installLocation = baseApk.installLocation;
this.verifiers = baseApk.verifiers;
this.splitNames = splitNames;
@@ -476,6 +478,7 @@
public final String configForSplit;
public final String usesSplitName;
public final int versionCode;
+ public final int versionCodeMajor;
public final int revisionCode;
public final int installLocation;
public final VerifierInfo[] verifiers;
@@ -489,11 +492,11 @@
public final boolean isolatedSplits;
public ApkLite(String codePath, String packageName, String splitName, boolean isFeatureSplit,
- String configForSplit, String usesSplitName, int versionCode, int revisionCode,
- int installLocation, List<VerifierInfo> verifiers, Signature[] signatures,
- Certificate[][] certificates, boolean coreApp, boolean debuggable,
- boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs,
- boolean isolatedSplits) {
+ String configForSplit, String usesSplitName, int versionCode, int versionCodeMajor,
+ int revisionCode, int installLocation, List<VerifierInfo> verifiers,
+ Signature[] signatures, Certificate[][] certificates, boolean coreApp,
+ boolean debuggable, boolean multiArch, boolean use32bitAbi,
+ boolean extractNativeLibs, boolean isolatedSplits) {
this.codePath = codePath;
this.packageName = packageName;
this.splitName = splitName;
@@ -501,6 +504,7 @@
this.configForSplit = configForSplit;
this.usesSplitName = usesSplitName;
this.versionCode = versionCode;
+ this.versionCodeMajor = versionCodeMajor;
this.revisionCode = revisionCode;
this.installLocation = installLocation;
this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
@@ -513,6 +517,10 @@
this.extractNativeLibs = extractNativeLibs;
this.isolatedSplits = isolatedSplits;
}
+
+ public long getLongVersionCode() {
+ return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode);
+ }
}
/**
@@ -663,6 +671,7 @@
pi.packageName = p.packageName;
pi.splitNames = p.splitNames;
pi.versionCode = p.mVersionCode;
+ pi.versionCodeMajor = p.mVersionCodeMajor;
pi.baseRevisionCode = p.baseRevisionCode;
pi.splitRevisionCodes = p.splitRevisionCodes;
pi.versionName = p.mVersionName;
@@ -1258,9 +1267,12 @@
}
}
- pkg.setCodePath(packageDir.getAbsolutePath());
+ pkg.setCodePath(packageDir.getCanonicalPath());
pkg.setUse32bitAbi(lite.use32bitAbi);
return pkg;
+ } catch (IOException e) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+ "Failed to get path: " + lite.baseCodePath, e);
} finally {
IoUtils.closeQuietly(assetLoader);
}
@@ -1289,9 +1301,12 @@
try {
final Package pkg = parseBaseApk(apkFile, assets, flags);
- pkg.setCodePath(apkFile.getAbsolutePath());
+ pkg.setCodePath(apkFile.getCanonicalPath());
pkg.setUse32bitAbi(lite.use32bitAbi);
return pkg;
+ } catch (IOException e) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+ "Failed to get path: " + apkFile, e);
} finally {
IoUtils.closeQuietly(assets);
}
@@ -1874,6 +1889,7 @@
int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
int versionCode = 0;
+ int versionCodeMajor = 0;
int revisionCode = 0;
boolean coreApp = false;
boolean debuggable = false;
@@ -1892,6 +1908,8 @@
PARSE_DEFAULT_INSTALL_LOCATION);
} else if (attr.equals("versionCode")) {
versionCode = attrs.getAttributeIntValue(i, 0);
+ } else if (attr.equals("versionCodeMajor")) {
+ versionCodeMajor = attrs.getAttributeIntValue(i, 0);
} else if (attr.equals("revisionCode")) {
revisionCode = attrs.getAttributeIntValue(i, 0);
} else if (attr.equals("coreApp")) {
@@ -1957,9 +1975,9 @@
}
return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
- configForSplit, usesSplitName, versionCode, revisionCode, installLocation,
- verifiers, signatures, certificates, coreApp, debuggable, multiArch, use32bitAbi,
- extractNativeLibs, isolatedSplits);
+ configForSplit, usesSplitName, versionCode, versionCodeMajor, revisionCode,
+ installLocation, verifiers, signatures, certificates, coreApp, debuggable,
+ multiArch, use32bitAbi, extractNativeLibs, isolatedSplits);
}
/**
@@ -2080,8 +2098,11 @@
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifest);
- pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
+ pkg.mVersionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
+ pkg.mVersionCodeMajor = sa.getInteger(
+ com.android.internal.R.styleable.AndroidManifest_versionCodeMajor, 0);
+ pkg.applicationInfo.versionCode = pkg.getLongVersionCode();
pkg.baseRevisionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
pkg.mVersionName = sa.getNonConfigurationString(
@@ -2906,7 +2927,7 @@
1, additionalCertSha256Digests.length);
pkg.usesStaticLibraries = ArrayUtils.add(pkg.usesStaticLibraries, lname);
- pkg.usesStaticLibrariesVersions = ArrayUtils.appendInt(
+ pkg.usesStaticLibrariesVersions = ArrayUtils.appendLong(
pkg.usesStaticLibrariesVersions, version, true);
pkg.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String[].class,
pkg.usesStaticLibrariesCertDigests, certSha256Digests, true);
@@ -3861,6 +3882,9 @@
com.android.internal.R.styleable.AndroidManifestStaticLibrary_name);
final int version = sa.getInt(
com.android.internal.R.styleable.AndroidManifestStaticLibrary_version, -1);
+ final int versionMajor = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestStaticLibrary_versionMajor,
+ 0);
sa.recycle();
@@ -3888,7 +3912,12 @@
}
owner.staticSharedLibName = lname.intern();
- owner.staticSharedLibVersion = version;
+ if (version >= 0) {
+ owner.staticSharedLibVersion =
+ PackageInfo.composeLongVersionCode(versionMajor, version);
+ } else {
+ owner.staticSharedLibVersion = version;
+ }
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY;
XmlUtils.skipCurrentTag(parser);
@@ -5889,11 +5918,11 @@
public ArrayList<Package> childPackages;
public String staticSharedLibName = null;
- public int staticSharedLibVersion = 0;
+ public long staticSharedLibVersion = 0;
public ArrayList<String> libraryNames = null;
public ArrayList<String> usesLibraries = null;
public ArrayList<String> usesStaticLibraries = null;
- public int[] usesStaticLibrariesVersions = null;
+ public long[] usesStaticLibrariesVersions = null;
public String[][] usesStaticLibrariesCertDigests = null;
public ArrayList<String> usesOptionalLibraries = null;
public String[] usesLibraryFiles = null;
@@ -5910,6 +5939,14 @@
// The version code declared for this package.
public int mVersionCode;
+ // The major version code declared for this package.
+ public int mVersionCodeMajor;
+
+ // Return long containing mVersionCode and mVersionCodeMajor.
+ public long getLongVersionCode() {
+ return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode);
+ }
+
// The version name declared for this package.
public String mVersionName;
@@ -6261,6 +6298,11 @@
}
/** @hide */
+ public boolean isVendor() {
+ return applicationInfo.isVendor();
+ }
+
+ /** @hide */
public boolean isPrivileged() {
return applicationInfo.isPrivilegedApp();
}
@@ -6379,7 +6421,7 @@
if (staticSharedLibName != null) {
staticSharedLibName = staticSharedLibName.intern();
}
- staticSharedLibVersion = dest.readInt();
+ staticSharedLibVersion = dest.readLong();
libraryNames = dest.createStringArrayList();
internStringArrayList(libraryNames);
usesLibraries = dest.createStringArrayList();
@@ -6393,8 +6435,8 @@
usesStaticLibraries = new ArrayList<>(libCount);
dest.readStringList(usesStaticLibraries);
internStringArrayList(usesStaticLibraries);
- usesStaticLibrariesVersions = new int[libCount];
- dest.readIntArray(usesStaticLibrariesVersions);
+ usesStaticLibrariesVersions = new long[libCount];
+ dest.readLongArray(usesStaticLibrariesVersions);
usesStaticLibrariesCertDigests = new String[libCount][];
for (int i = 0; i < libCount; i++) {
usesStaticLibrariesCertDigests[i] = dest.createStringArray();
@@ -6534,7 +6576,7 @@
dest.writeParcelableList(childPackages, flags);
dest.writeString(staticSharedLibName);
- dest.writeInt(staticSharedLibVersion);
+ dest.writeLong(staticSharedLibVersion);
dest.writeStringList(libraryNames);
dest.writeStringList(usesLibraries);
dest.writeStringList(usesOptionalLibraries);
@@ -6545,7 +6587,7 @@
} else {
dest.writeInt(usesStaticLibraries.size());
dest.writeStringList(usesStaticLibraries);
- dest.writeIntArray(usesStaticLibrariesVersions);
+ dest.writeLongArray(usesStaticLibrariesVersions);
for (String[] usesStaticLibrariesCertDigest : usesStaticLibrariesCertDigests) {
dest.writeStringArray(usesStaticLibrariesCertDigest);
}
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 7588762..551d53b 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -144,6 +144,15 @@
public static final int PROTECTION_FLAG_OEM = 0x4000;
/**
+ * Additional flag for {${link #protectionLevel}, corresponding
+ * to the <code>vendorPrivileged</code> value of
+ * {@link android.R.attr#protectionLevel}.
+ *
+ * @hide
+ */
+ public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 0x8000;
+
+ /**
* Mask for {@link #protectionLevel}: the basic protection type.
*/
public static final int PROTECTION_MASK_BASE = 0xf;
@@ -231,6 +240,12 @@
if (level == PROTECTION_SIGNATURE_OR_SYSTEM) {
level = PROTECTION_SIGNATURE | PROTECTION_FLAG_PRIVILEGED;
}
+ if ((level & PROTECTION_FLAG_VENDOR_PRIVILEGED) != 0
+ && (level & PROTECTION_FLAG_PRIVILEGED) == 0) {
+ // 'vendorPrivileged' must be 'privileged'. If not,
+ // drop the vendorPrivileged.
+ level = level & ~PROTECTION_FLAG_VENDOR_PRIVILEGED;
+ }
return level;
}
@@ -284,6 +299,9 @@
if ((level & PermissionInfo.PROTECTION_FLAG_OEM) != 0) {
protLevel += "|oem";
}
+ if ((level & PermissionInfo.PROTECTION_FLAG_VENDOR_PRIVILEGED) != 0) {
+ protLevel += "|vendorPrivileged";
+ }
return protLevel;
}
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index aea843a..56d61ef 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -361,7 +361,7 @@
}
IntArray updatedUids = null;
for (ServiceInfo<V> service : allServices) {
- int versionCode = service.componentInfo.applicationInfo.versionCode;
+ long versionCode = service.componentInfo.applicationInfo.versionCode;
String pkg = service.componentInfo.packageName;
ApplicationInfo newAppInfo = null;
try {
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index 7d301a3..2f1b256 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -73,8 +73,7 @@
private final String mName;
- // TODO: Make long when we change the paltform to use longs
- private final int mVersion;
+ private final long mVersion;
private final @Type int mType;
private final VersionedPackage mDeclaringPackage;
private final List<VersionedPackage> mDependentPackages;
@@ -90,7 +89,7 @@
*
* @hide
*/
- public SharedLibraryInfo(String name, int version, int type,
+ public SharedLibraryInfo(String name, long version, int type,
VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages) {
mName = name;
mVersion = version;
@@ -100,7 +99,7 @@
}
private SharedLibraryInfo(Parcel parcel) {
- this(parcel.readString(), parcel.readInt(), parcel.readInt(),
+ this(parcel.readString(), parcel.readLong(), parcel.readInt(),
parcel.readParcelable(null), parcel.readArrayList(null));
}
@@ -124,6 +123,14 @@
}
/**
+ * @deprecated Use {@link #getLongVersion()} instead.
+ */
+ @Deprecated
+ public @IntRange(from = -1) int getVersion() {
+ return mVersion < 0 ? (int) mVersion : (int) (mVersion & 0x7fffffff);
+ }
+
+ /**
* Gets the version of the library. For {@link #TYPE_STATIC static} libraries
* this is the declared version and for {@link #TYPE_DYNAMIC dynamic} and
* {@link #TYPE_BUILTIN builtin} it is {@link #VERSION_UNDEFINED} as these
@@ -131,7 +138,7 @@
*
* @return The version.
*/
- public @IntRange(from = -1) int getVersion() {
+ public @IntRange(from = -1) long getLongVersion() {
return mVersion;
}
@@ -192,7 +199,7 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(mName);
- parcel.writeInt(mVersion);
+ parcel.writeLong(mVersion);
parcel.writeInt(mType);
parcel.writeParcelable(mDeclaringPackage, flags);
parcel.writeList(mDependentPackages);
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index dadfaa9..e6f682d 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -81,4 +81,7 @@
@Nullable IntentSender resultIntent, int userId);
public abstract boolean isRequestPinItemSupported(int callingUserId, int requestType);
+
+ public abstract boolean isForegroundDefaultLauncher(@NonNull String callingPackage,
+ int callingUid);
}
diff --git a/core/java/android/content/pm/VersionedPackage.java b/core/java/android/content/pm/VersionedPackage.java
index 29c5efe..3953466 100644
--- a/core/java/android/content/pm/VersionedPackage.java
+++ b/core/java/android/content/pm/VersionedPackage.java
@@ -28,7 +28,7 @@
*/
public final class VersionedPackage implements Parcelable {
private final String mPackageName;
- private final int mVersionCode;
+ private final long mVersionCode;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -47,9 +47,21 @@
mVersionCode = versionCode;
}
+ /**
+ * Creates a new instance. Use {@link PackageManager#VERSION_CODE_HIGHEST}
+ * to refer to the highest version code of this package.
+ * @param packageName The package name.
+ * @param versionCode The version code.
+ */
+ public VersionedPackage(@NonNull String packageName,
+ @VersionCode long versionCode) {
+ mPackageName = packageName;
+ mVersionCode = versionCode;
+ }
+
private VersionedPackage(Parcel parcel) {
mPackageName = parcel.readString();
- mVersionCode = parcel.readInt();
+ mVersionCode = parcel.readLong();
}
/**
@@ -62,11 +74,19 @@
}
/**
+ * @deprecated use {@link #getLongVersionCode()} instead.
+ */
+ @Deprecated
+ public @VersionCode int getVersionCode() {
+ return (int) (mVersionCode & 0x7fffffff);
+ }
+
+ /**
* Gets the version code.
*
* @return The version code.
*/
- public @VersionCode int getVersionCode() {
+ public @VersionCode long getLongVersionCode() {
return mVersionCode;
}
@@ -83,7 +103,7 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(mPackageName);
- parcel.writeInt(mVersionCode);
+ parcel.writeLong(mVersionCode);
}
public static final Creator<VersionedPackage> CREATOR = new Creator<VersionedPackage>() {
diff --git a/core/java/android/content/pm/crossprofile/CrossProfileApps.java b/core/java/android/content/pm/crossprofile/CrossProfileApps.java
index c441b5f..c9f184a 100644
--- a/core/java/android/content/pm/crossprofile/CrossProfileApps.java
+++ b/core/java/android/content/pm/crossprofile/CrossProfileApps.java
@@ -19,12 +19,17 @@
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import com.android.internal.R;
+import com.android.internal.util.UserIcons;
+
import java.util.List;
/**
@@ -35,11 +40,15 @@
public class CrossProfileApps {
private final Context mContext;
private final ICrossProfileApps mService;
+ private final UserManager mUserManager;
+ private final Resources mResources;
/** @hide */
public CrossProfileApps(Context context, ICrossProfileApps service) {
mContext = context;
mService = service;
+ mUserManager = context.getSystemService(UserManager.class);
+ mResources = context.getResources();
}
/**
@@ -87,4 +96,58 @@
throw ex.rethrowFromSystemServer();
}
}
+
+ /**
+ * Return a label that calling app can show to user for the semantic of profile switching --
+ * launching its own activity in specified user profile. For example, it may return
+ * "Switch to work" if the given user handle is the managed profile one.
+ *
+ * @param userHandle The UserHandle of the target profile, must be one of the users returned by
+ * {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will
+ * be thrown.
+ * @return a label that calling app can show user for the semantic of launching its own
+ * activity in the specified user profile.
+ *
+ * @see #startMainActivity(ComponentName, UserHandle, Rect, Bundle)
+ */
+ public @NonNull CharSequence getProfileSwitchingLabel(@NonNull UserHandle userHandle) {
+ verifyCanAccessUser(userHandle);
+
+ final int stringRes = mUserManager.isManagedProfile(userHandle.getIdentifier())
+ ? R.string.managed_profile_label
+ : R.string.user_owner_label;
+ return mResources.getString(stringRes);
+ }
+
+ /**
+ * Return an icon that calling app can show to user for the semantic of profile switching --
+ * launching its own activity in specified user profile. For example, it may return a briefcase
+ * icon if the given user handle is the managed profile one.
+ *
+ * @param userHandle The UserHandle of the target profile, must be one of the users returned by
+ * {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will
+ * be thrown.
+ * @return an icon that calling app can show user for the semantic of launching its own
+ * activity in specified user profile.
+ *
+ * @see #startMainActivity(ComponentName, UserHandle, Rect, Bundle)
+ */
+ public @NonNull Drawable getProfileSwitchingIcon(@NonNull UserHandle userHandle) {
+ verifyCanAccessUser(userHandle);
+
+ final boolean isManagedProfile =
+ mUserManager.isManagedProfile(userHandle.getIdentifier());
+ if (isManagedProfile) {
+ return mResources.getDrawable(R.drawable.ic_corp_badge, null);
+ } else {
+ return UserIcons.getDefaultUserIcon(
+ mResources, UserHandle.USER_SYSTEM, true /* light */);
+ }
+ }
+
+ private void verifyCanAccessUser(UserHandle userHandle) {
+ if (!getTargetUserProfiles().contains(userHandle)) {
+ throw new SecurityException("Not allowed to access " + userHandle);
+ }
+ }
}
diff --git a/core/java/android/content/pm/dex/ArtManager.java b/core/java/android/content/pm/dex/ArtManager.java
new file mode 100644
index 0000000..201cd8d
--- /dev/null
+++ b/core/java/android/content/pm/dex/ArtManager.java
@@ -0,0 +1,156 @@
+/**
+ * Copyright 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 android.content.pm.dex;
+
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.Slog;
+
+/**
+ * Class for retrieving various kinds of information related to the runtime artifacts of
+ * packages that are currently installed on the device.
+ *
+ * @hide
+ */
+@SystemApi
+public class ArtManager {
+ private static final String TAG = "ArtManager";
+
+ /** The snapshot failed because the package was not found. */
+ public static final int SNAPSHOT_FAILED_PACKAGE_NOT_FOUND = 0;
+ /** The snapshot failed because the package code path does not exist. */
+ public static final int SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND = 1;
+ /** The snapshot failed because of an internal error (e.g. error during opening profiles). */
+ public static final int SNAPSHOT_FAILED_INTERNAL_ERROR = 2;
+
+ private IArtManager mArtManager;
+
+ /**
+ * @hide
+ */
+ public ArtManager(@NonNull IArtManager manager) {
+ mArtManager = manager;
+ }
+
+ /**
+ * Snapshots the runtime profile for an apk belonging to the package {@code packageName}.
+ * The apk is identified by {@code codePath}. The calling process must have
+ * {@code android.permission.READ_RUNTIME_PROFILE} permission.
+ *
+ * The result will be posted on {@code handler} using the given {@code callback}.
+ * The profile being available as a read-only {@link android.os.ParcelFileDescriptor}.
+ *
+ * @param packageName the target package name
+ * @param codePath the code path for which the profile should be retrieved
+ * @param callback the callback which should be used for the result
+ * @param handler the handler which should be used to post the result
+ */
+ @RequiresPermission(android.Manifest.permission.READ_RUNTIME_PROFILES)
+ public void snapshotRuntimeProfile(@NonNull String packageName, @NonNull String codePath,
+ @NonNull SnapshotRuntimeProfileCallback callback, @NonNull Handler handler) {
+ Slog.d(TAG, "Requesting profile snapshot for " + packageName + ":" + codePath);
+
+ SnapshotRuntimeProfileCallbackDelegate delegate =
+ new SnapshotRuntimeProfileCallbackDelegate(callback, handler.getLooper());
+ try {
+ mArtManager.snapshotRuntimeProfile(packageName, codePath, delegate);
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Returns true if runtime profiles are enabled, false otherwise.
+ *
+ * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_RUNTIME_PROFILES)
+ public boolean isRuntimeProfilingEnabled() {
+ try {
+ return mArtManager.isRuntimeProfilingEnabled();
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ return false;
+ }
+
+ /**
+ * Callback used for retrieving runtime profiles.
+ */
+ public abstract static class SnapshotRuntimeProfileCallback {
+ /**
+ * Called when the profile snapshot finished with success.
+ *
+ * @param profileReadFd the file descriptor that can be used to read the profile. Note that
+ * the file might be empty (which is valid profile).
+ */
+ public abstract void onSuccess(ParcelFileDescriptor profileReadFd);
+
+ /**
+ * Called when the profile snapshot finished with an error.
+ *
+ * @param errCode the error code {@see SNAPSHOT_FAILED_PACKAGE_NOT_FOUND,
+ * SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND, SNAPSHOT_FAILED_INTERNAL_ERROR}.
+ */
+ public abstract void onError(int errCode);
+ }
+
+ private static class SnapshotRuntimeProfileCallbackDelegate
+ extends android.content.pm.dex.ISnapshotRuntimeProfileCallback.Stub
+ implements Handler.Callback {
+ private static final int MSG_SNAPSHOT_OK = 1;
+ private static final int MSG_ERROR = 2;
+ private final ArtManager.SnapshotRuntimeProfileCallback mCallback;
+ private final Handler mHandler;
+
+ private SnapshotRuntimeProfileCallbackDelegate(
+ ArtManager.SnapshotRuntimeProfileCallback callback, Looper looper) {
+ mCallback = callback;
+ mHandler = new Handler(looper, this);
+ }
+
+ @Override
+ public void onSuccess(ParcelFileDescriptor profileReadFd) {
+ mHandler.obtainMessage(MSG_SNAPSHOT_OK, profileReadFd).sendToTarget();
+ }
+
+ @Override
+ public void onError(int errCode) {
+ mHandler.obtainMessage(MSG_ERROR, errCode, 0).sendToTarget();
+ }
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SNAPSHOT_OK:
+ mCallback.onSuccess((ParcelFileDescriptor) msg.obj);
+ break;
+ case MSG_ERROR:
+ mCallback.onError(msg.arg1);
+ break;
+ default: return false;
+ }
+ return true;
+ }
+ }
+}
diff --git a/core/java/android/content/pm/dex/IArtManager.aidl b/core/java/android/content/pm/dex/IArtManager.aidl
new file mode 100644
index 0000000..8cbb452
--- /dev/null
+++ b/core/java/android/content/pm/dex/IArtManager.aidl
@@ -0,0 +1,44 @@
+/*
+** Copyright 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 android.content.pm.dex;
+
+import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
+
+/**
+ * A system service that provides access to runtime and compiler artifacts.
+ *
+ * @hide
+ */
+interface IArtManager {
+ /**
+ * Snapshots the runtime profile for an apk belonging to the package {@param packageName}.
+ * The apk is identified by {@param codePath}. The calling process must have
+ * {@code android.permission.READ_RUNTIME_PROFILE} permission.
+ *
+ * The result will be posted on {@param callback} with the profile being available as a
+ * read-only {@link android.os.ParcelFileDescriptor}.
+ */
+ oneway void snapshotRuntimeProfile(in String packageName,
+ in String codePath, in ISnapshotRuntimeProfileCallback callback);
+
+ /**
+ * Returns true if runtime profiles are enabled, false otherwise.
+ *
+ * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission.
+ */
+ boolean isRuntimeProfilingEnabled();
+}
diff --git a/core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl b/core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl
new file mode 100644
index 0000000..3b4838f
--- /dev/null
+++ b/core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl
@@ -0,0 +1,29 @@
+/*
+** Copyright 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 android.content.pm.dex;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Callback used to post the result of a profile-snapshot operation.
+ *
+ * @hide
+ */
+oneway interface ISnapshotRuntimeProfileCallback {
+ void onSuccess(in ParcelFileDescriptor profileReadFd);
+ void onError(int errCode);
+}
diff --git a/core/java/android/content/res/AssetFileDescriptor.java b/core/java/android/content/res/AssetFileDescriptor.java
index 28edde0..be41036 100644
--- a/core/java/android/content/res/AssetFileDescriptor.java
+++ b/core/java/android/content/res/AssetFileDescriptor.java
@@ -195,7 +195,7 @@
/**
* An InputStream you can create on a ParcelFileDescriptor, which will
* take care of calling {@link ParcelFileDescriptor#close
- * ParcelFileDescritor.close()} for you when the stream is closed.
+ * ParcelFileDescriptor.close()} for you when the stream is closed.
*/
public static class AutoCloseInputStream
extends ParcelFileDescriptor.AutoCloseInputStream {
@@ -282,7 +282,7 @@
/**
* An OutputStream you can create on a ParcelFileDescriptor, which will
* take care of calling {@link ParcelFileDescriptor#close
- * ParcelFileDescritor.close()} for you when the stream is closed.
+ * ParcelFileDescriptor.close()} for you when the stream is closed.
*/
public static class AutoCloseOutputStream
extends ParcelFileDescriptor.AutoCloseOutputStream {
diff --git a/core/java/android/content/res/XmlResourceParser.java b/core/java/android/content/res/XmlResourceParser.java
index 5af49d4..6be9b9e 100644
--- a/core/java/android/content/res/XmlResourceParser.java
+++ b/core/java/android/content/res/XmlResourceParser.java
@@ -16,20 +16,19 @@
package android.content.res;
-import org.xmlpull.v1.XmlPullParser;
-
import android.util.AttributeSet;
+import org.xmlpull.v1.XmlPullParser;
+
/**
* The XML parsing interface returned for an XML resource. This is a standard
- * XmlPullParser interface, as well as an extended AttributeSet interface and
- * an additional close() method on this interface for the client to indicate
- * when it is done reading the resource.
+ * {@link XmlPullParser} interface but also extends {@link AttributeSet} and
+ * adds an additional {@link #close()} method for the client to indicate when
+ * it is done reading the resource.
*/
public interface XmlResourceParser extends XmlPullParser, AttributeSet, AutoCloseable {
/**
- * Close this interface to the resource. Calls on the interface are no
- * longer value after this call.
+ * Close this parser. Calls on the interface are no longer valid after this call.
*/
public void close();
}
diff --git a/core/java/android/database/OWNERS b/core/java/android/database/OWNERS
new file mode 100644
index 0000000..84e81e4
--- /dev/null
+++ b/core/java/android/database/OWNERS
@@ -0,0 +1,2 @@
+fkupolov@google.com
+omakoto@google.com
\ No newline at end of file
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 4b57018..cb11d0f 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2725,6 +2725,22 @@
public static final int CONTROL_AWB_STATE_LOCKED = 3;
//
+ // Enumeration values for CaptureResult#CONTROL_AF_SCENE_CHANGE
+ //
+
+ /**
+ * <p>Scene change is not detected within the AF region(s).</p>
+ * @see CaptureResult#CONTROL_AF_SCENE_CHANGE
+ */
+ public static final int CONTROL_AF_SCENE_CHANGE_NOT_DETECTED = 0;
+
+ /**
+ * <p>Scene change is detected within the AF region(s).</p>
+ * @see CaptureResult#CONTROL_AF_SCENE_CHANGE
+ */
+ public static final int CONTROL_AF_SCENE_CHANGE_DETECTED = 1;
+
+ //
// Enumeration values for CaptureResult#FLASH_STATE
//
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index cfad098..6d7b06f 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2185,6 +2185,30 @@
new Key<Boolean>("android.control.enableZsl", boolean.class);
/**
+ * <p>Whether a significant scene change is detected within the currently-set AF
+ * region(s).</p>
+ * <p>When the camera focus routine detects a change in the scene it is looking at,
+ * such as a large shift in camera viewpoint, significant motion in the scene, or a
+ * significant illumination change, this value will be set to DETECTED for a single capture
+ * result. Otherwise the value will be NOT_DETECTED. The threshold for detection is similar
+ * to what would trigger a new passive focus scan to begin in CONTINUOUS autofocus modes.</p>
+ * <p>afSceneChange may be DETECTED only if afMode is AF_MODE_CONTINUOUS_VIDEO or
+ * AF_MODE_CONTINUOUS_PICTURE. In other AF modes, afSceneChange must be NOT_DETECTED.</p>
+ * <p>This key will be available if the camera device advertises this key via {@link android.hardware.camera2.CameraCharacteristics#getAvailableCaptureResultKeys }.</p>
+ * <p><b>Possible values:</b>
+ * <ul>
+ * <li>{@link #CONTROL_AF_SCENE_CHANGE_NOT_DETECTED NOT_DETECTED}</li>
+ * <li>{@link #CONTROL_AF_SCENE_CHANGE_DETECTED DETECTED}</li>
+ * </ul></p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * @see #CONTROL_AF_SCENE_CHANGE_NOT_DETECTED
+ * @see #CONTROL_AF_SCENE_CHANGE_DETECTED
+ */
+ @PublicKey
+ public static final Key<Integer> CONTROL_AF_SCENE_CHANGE =
+ new Key<Integer>("android.control.afSceneChange", int.class);
+
+ /**
* <p>Operation mode for edge
* enhancement.</p>
* <p>Edge enhancement improves sharpness and details in the captured image. OFF means
diff --git a/core/java/android/hardware/display/BrightnessChangeEvent.java b/core/java/android/hardware/display/BrightnessChangeEvent.java
index fe24e32..3003607 100644
--- a/core/java/android/hardware/display/BrightnessChangeEvent.java
+++ b/core/java/android/hardware/display/BrightnessChangeEvent.java
@@ -21,6 +21,8 @@
/**
* Data about a brightness settings change.
+ *
+ * {@see DisplayManager.getBrightnessEvents()}
* TODO make this SystemAPI
* @hide
*/
@@ -31,7 +33,9 @@
/** Timestamp of the change {@see System.currentTimeMillis()} */
public long timeStamp;
- /** Package name of focused activity when brightness was changed. */
+ /** Package name of focused activity when brightness was changed.
+ * This will be null if the caller of {@see DisplayManager.getBrightnessEvents()}
+ * does not have access to usage stats {@see UsageStatsManager} */
public String packageName;
/** User id of of the user running when brightness was changed.
@@ -59,6 +63,20 @@
public BrightnessChangeEvent() {
}
+ /** @hide */
+ public BrightnessChangeEvent(BrightnessChangeEvent other) {
+ this.brightness = other.brightness;
+ this.timeStamp = other.timeStamp;
+ this.packageName = other.packageName;
+ this.userId = other.userId;
+ this.luxValues = other.luxValues;
+ this.luxTimestamps = other.luxTimestamps;
+ this.batteryLevel = other.batteryLevel;
+ this.nightMode = other.nightMode;
+ this.colorTemperature = other.colorTemperature;
+ this.lastBrightness = other.lastBrightness;
+ }
+
private BrightnessChangeEvent(Parcel source) {
brightness = source.readInt();
timeStamp = source.readLong();
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 8935745..97ca231 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -16,8 +16,10 @@
package android.hardware.display;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.KeyguardManager;
@@ -619,8 +621,9 @@
* Fetch {@link BrightnessChangeEvent}s.
* @hide until we make it a system api.
*/
+ @RequiresPermission(Manifest.permission.BRIGHTNESS_SLIDER_USAGE)
public List<BrightnessChangeEvent> getBrightnessEvents() {
- return mGlobal.getBrightnessEvents();
+ return mGlobal.getBrightnessEvents(mContext.getOpPackageName());
}
/**
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index d93d0e4..c3f82f5 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -462,9 +462,10 @@
/**
* Retrieves brightness change events.
*/
- public List<BrightnessChangeEvent> getBrightnessEvents() {
+ public List<BrightnessChangeEvent> getBrightnessEvents(String callingPackage) {
try {
- ParceledListSlice<BrightnessChangeEvent> events = mDm.getBrightnessEvents();
+ ParceledListSlice<BrightnessChangeEvent> events =
+ mDm.getBrightnessEvents(callingPackage);
if (events == null) {
return Collections.emptyList();
}
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index b796cf9..f2ed9e7 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -84,7 +84,7 @@
Point getStableDisplaySize();
// Requires BRIGHTNESS_SLIDER_USAGE permission.
- ParceledListSlice getBrightnessEvents();
+ ParceledListSlice getBrightnessEvents(String callingPackage);
// STOPSHIP remove when adaptive brightness code is updated to accept curves.
// Requires BRIGHTNESS_SLIDER_USAGE permission.
diff --git a/core/java/android/hardware/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java
index b7e353a..52527ed 100644
--- a/core/java/android/hardware/location/ContextHubClient.java
+++ b/core/java/android/hardware/location/ContextHubClient.java
@@ -16,43 +16,48 @@
package android.hardware.location;
import android.annotation.RequiresPermission;
-import android.os.Handler;
+import android.os.RemoteException;
+
+import dalvik.system.CloseGuard;
import java.io.Closeable;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* A class describing a client of the Context Hub Service.
*
- * Clients can send messages to nanoapps at a Context Hub through this object.
+ * Clients can send messages to nanoapps at a Context Hub through this object. The APIs supported
+ * by this object are thread-safe and can be used without external synchronization.
*
* @hide
*/
public class ContextHubClient implements Closeable {
/*
- * The ContextHubClient interface associated with this client.
+ * The proxy to the client interface at the service.
*/
- // TODO: Implement this interface and associate with ContextHubClient object
- // private final IContextHubClient mClientInterface;
+ private final IContextHubClient mClientProxy;
/*
- * The listening callback associated with this client.
+ * The callback interface associated with this client.
*/
- private ContextHubClientCallback mCallback;
+ private final IContextHubClientCallback mCallbackInterface;
/*
* The Context Hub that this client is attached to.
*/
- private ContextHubInfo mAttachedHub;
+ private final ContextHubInfo mAttachedHub;
- /*
- * The handler to invoke mCallback.
- */
- private Handler mCallbackHandler;
+ private final CloseGuard mCloseGuard = CloseGuard.get();
- ContextHubClient(ContextHubClientCallback callback, Handler handler, ContextHubInfo hubInfo) {
- mCallback = callback;
- mCallbackHandler = handler;
+ private final AtomicBoolean mIsClosed = new AtomicBoolean(false);
+
+ /* package */ ContextHubClient(
+ IContextHubClient clientProxy, IContextHubClientCallback callback,
+ ContextHubInfo hubInfo) {
+ mClientProxy = clientProxy;
+ mCallbackInterface = callback;
mAttachedHub = hubInfo;
+ mCloseGuard.open("close");
}
/**
@@ -71,7 +76,14 @@
* All futures messages targeted for this client are dropped at the service.
*/
public void close() {
- throw new UnsupportedOperationException("TODO: Implement this");
+ if (!mIsClosed.getAndSet(true)) {
+ mCloseGuard.close();
+ try {
+ mClientProxy.close();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
/**
@@ -90,6 +102,22 @@
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
@ContextHubTransaction.Result
public int sendMessageToNanoApp(NanoAppMessage message) {
- throw new UnsupportedOperationException("TODO: Implement this");
+ try {
+ return mClientProxy.sendMessageToNanoApp(message);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ close();
+ } finally {
+ super.finalize();
+ }
}
}
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 2411727..b31c7bc 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -456,6 +456,54 @@
}
/**
+ * Creates an interface to the ContextHubClient to send down to the service.
+ *
+ * @param callback the callback to invoke at the client process
+ * @param handler the handler to post callbacks for this client
+ *
+ * @return the callback interface
+ */
+ private IContextHubClientCallback createClientCallback(
+ ContextHubClientCallback callback, Handler handler) {
+ return new IContextHubClientCallback.Stub() {
+ @Override
+ public void onMessageFromNanoApp(NanoAppMessage message) {
+ handler.post(() -> callback.onMessageFromNanoApp(message));
+ }
+
+ @Override
+ public void onHubReset() {
+ handler.post(() -> callback.onHubReset());
+ }
+
+ @Override
+ public void onNanoAppAborted(long nanoAppId, int abortCode) {
+ handler.post(() -> callback.onNanoAppAborted(nanoAppId, abortCode));
+ }
+
+ @Override
+ public void onNanoAppLoaded(long nanoAppId) {
+ handler.post(() -> callback.onNanoAppLoaded(nanoAppId));
+ }
+
+ @Override
+ public void onNanoAppUnloaded(long nanoAppId) {
+ handler.post(() -> callback.onNanoAppUnloaded(nanoAppId));
+ }
+
+ @Override
+ public void onNanoAppEnabled(long nanoAppId) {
+ handler.post(() -> callback.onNanoAppEnabled(nanoAppId));
+ }
+
+ @Override
+ public void onNanoAppDisabled(long nanoAppId) {
+ handler.post(() -> callback.onNanoAppDisabled(nanoAppId));
+ }
+ };
+ }
+
+ /**
* Creates and registers a client and its callback with the Context Hub Service.
*
* A client is registered with the Context Hub Service for a specified Context Hub. When the
@@ -463,19 +511,37 @@
* {@link ContextHubClient} object, and receive notifications through the provided callback.
*
* @param callback the notification callback to register
- * @param hubInfo the hub to attach this client to
- * @param handler the handler to invoke the callback, if null uses the main thread's Looper
- *
+ * @param hubInfo the hub to attach this client to
+ * @param handler the handler to invoke the callback, if null uses the main thread's Looper
* @return the registered client object
*
- * @see ContextHubClientCallback
+ * @throws IllegalArgumentException if hubInfo does not represent a valid hub
+ * @throws IllegalStateException if there were too many registered clients at the service
+ * @throws NullPointerException if callback or hubInfo is null
*
* @hide
+ * @see ContextHubClientCallback
*/
public ContextHubClient createClient(
ContextHubClientCallback callback, ContextHubInfo hubInfo, @Nullable Handler handler) {
- throw new UnsupportedOperationException(
- "TODO: Implement this, and throw an exception on error");
+ if (callback == null) {
+ throw new NullPointerException("Callback cannot be null");
+ }
+ if (hubInfo == null) {
+ throw new NullPointerException("Hub info cannot be null");
+ }
+
+ Handler realHandler = (handler == null) ? new Handler(mMainLooper) : handler;
+ IContextHubClientCallback clientInterface = createClientCallback(callback, realHandler);
+
+ IContextHubClient client;
+ try {
+ client = mService.createClient(clientInterface, hubInfo.getId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ return new ContextHubClient(client, clientInterface, hubInfo);
}
/**
diff --git a/core/java/android/print/IPrintClient.aidl b/core/java/android/hardware/location/IContextHubClient.aidl
similarity index 63%
copy from core/java/android/print/IPrintClient.aidl
copy to core/java/android/hardware/location/IContextHubClient.aidl
index 3f39d08..d81126a 100644
--- a/core/java/android/print/IPrintClient.aidl
+++ b/core/java/android/hardware/location/IContextHubClient.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright 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.
@@ -14,17 +14,18 @@
* limitations under the License.
*/
-package android.print;
+package android.hardware.location;
-import android.content.IntentSender;
+import android.hardware.location.NanoAppMessage;
/**
- * Interface for communication with a printing app.
- *
- * @see android.print.IPrintClientCallback
- *
* @hide
*/
-oneway interface IPrintClient {
- void startPrintJobConfigActivity(in IntentSender intent);
+interface IContextHubClient {
+
+ // Sends a message to a nanoapp
+ int sendMessageToNanoApp(in NanoAppMessage message);
+
+ // Closes the connection with the Context Hub
+ void close();
}
diff --git a/core/java/android/hardware/location/IContextHubClientCallback.aidl b/core/java/android/hardware/location/IContextHubClientCallback.aidl
new file mode 100644
index 0000000..1c76bcb
--- /dev/null
+++ b/core/java/android/hardware/location/IContextHubClientCallback.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright 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 android.hardware.location;
+
+import android.hardware.location.NanoAppMessage;
+
+/**
+ * An interface used by the Context Hub Service to invoke callbacks for lifecycle notifications of a
+ * Context Hub and nanoapps, as well as for nanoapp messaging.
+ *
+ * @hide
+ */
+oneway interface IContextHubClientCallback {
+
+ // Callback invoked when receiving a message from a nanoapp.
+ void onMessageFromNanoApp(in NanoAppMessage message);
+
+ // Callback invoked when the attached Context Hub has reset.
+ void onHubReset();
+
+ // Callback invoked when a nanoapp aborts at the attached Context Hub.
+ void onNanoAppAborted(long nanoAppId, int abortCode);
+
+ // Callback invoked when a nanoapp is loaded at the attached Context Hub.
+ void onNanoAppLoaded(long nanoAppId);
+
+ // Callback invoked when a nanoapp is unloaded from the attached Context Hub.
+ void onNanoAppUnloaded(long nanoAppId);
+
+ // Callback invoked when a nanoapp is enabled at the attached Context Hub.
+ void onNanoAppEnabled(long nanoAppId);
+
+ // Callback invoked when a nanoapp is disabled at the attached Context Hub.
+ void onNanoAppDisabled(long nanoAppId);
+}
diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl
index ff8c1d0..1bb7c8f 100644
--- a/core/java/android/hardware/location/IContextHubService.aidl
+++ b/core/java/android/hardware/location/IContextHubService.aidl
@@ -17,12 +17,14 @@
package android.hardware.location;
// Declare any non-default types here with import statements
-import android.hardware.location.ContextHubMessage;
import android.hardware.location.ContextHubInfo;
+import android.hardware.location.ContextHubMessage;
import android.hardware.location.NanoApp;
-import android.hardware.location.NanoAppInstanceInfo;
import android.hardware.location.NanoAppFilter;
+import android.hardware.location.NanoAppInstanceInfo;
import android.hardware.location.IContextHubCallback;
+import android.hardware.location.IContextHubClient;
+import android.hardware.location.IContextHubClientCallback;
/**
* @hide
@@ -52,4 +54,7 @@
// send a message to a nanoApp
int sendMessage(int hubHandle, int nanoAppHandle, in ContextHubMessage msg);
+
+ // Creates a client to send and receive messages
+ IContextHubClient createClient(in IContextHubClientCallback client, int contextHubId);
}
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
index bf35a3d..5ccf546 100644
--- a/core/java/android/hardware/location/NanoAppFilter.java
+++ b/core/java/android/hardware/location/NanoAppFilter.java
@@ -20,7 +20,6 @@
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Log;
/**
* @hide
@@ -130,6 +129,14 @@
(versionsMatch(mVersionRestrictionMask, mAppVersion, info.getAppVersion()));
}
+ @Override
+ public String toString() {
+ return "nanoAppId: 0x" + Long.toHexString(mAppId)
+ + ", nanoAppVersion: 0x" + Integer.toHexString(mAppVersion)
+ + ", versionMask: " + mVersionRestrictionMask
+ + ", vendorMask: " + mAppIdVendorMask;
+ }
+
public static final Parcelable.Creator<NanoAppFilter> CREATOR
= new Parcelable.Creator<NanoAppFilter>() {
public NanoAppFilter createFromParcel(Parcel in) {
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index d6e62cf..f82627b 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -21,6 +21,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.HexDump;
import java.lang.annotation.Retention;
@@ -34,6 +35,8 @@
* Internet Protocol</a>
*/
public final class IpSecAlgorithm implements Parcelable {
+ private static final String TAG = "IpSecAlgorithm";
+
/**
* AES-CBC Encryption/Ciphering Algorithm.
*
@@ -45,6 +48,7 @@
* MD5 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in
* new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
*
+ * <p>Keys for this algorithm must be 128 bits in length.
* <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 128.
*/
public static final String AUTH_HMAC_MD5 = "hmac(md5)";
@@ -53,6 +57,7 @@
* SHA1 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in
* new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
*
+ * <p>Keys for this algorithm must be 160 bits in length.
* <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 160.
*/
public static final String AUTH_HMAC_SHA1 = "hmac(sha1)";
@@ -60,6 +65,7 @@
/**
* SHA256 HMAC Authentication/Integrity Algorithm.
*
+ * <p>Keys for this algorithm must be 256 bits in length.
* <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 256.
*/
public static final String AUTH_HMAC_SHA256 = "hmac(sha256)";
@@ -67,6 +73,7 @@
/**
* SHA384 HMAC Authentication/Integrity Algorithm.
*
+ * <p>Keys for this algorithm must be 384 bits in length.
* <p>Valid truncation lengths are multiples of 8 bits from 192 to (default) 384.
*/
public static final String AUTH_HMAC_SHA384 = "hmac(sha384)";
@@ -74,6 +81,7 @@
/**
* SHA512 HMAC Authentication/Integrity Algorithm.
*
+ * <p>Keys for this algorithm must be 512 bits in length.
* <p>Valid truncation lengths are multiples of 8 bits from 256 to (default) 512.
*/
public static final String AUTH_HMAC_SHA512 = "hmac(sha512)";
@@ -130,12 +138,10 @@
* @param truncLenBits number of bits of output hash to use.
*/
public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) {
- if (!isTruncationLengthValid(algorithm, truncLenBits)) {
- throw new IllegalArgumentException("Unknown algorithm or invalid length");
- }
mName = algorithm;
mKey = key.clone();
- mTruncLenBits = Math.min(truncLenBits, key.length * 8);
+ mTruncLenBits = truncLenBits;
+ checkValidOrThrow(mName, mKey.length * 8, mTruncLenBits);
}
/** Get the algorithm name */
@@ -169,7 +175,11 @@
public static final Parcelable.Creator<IpSecAlgorithm> CREATOR =
new Parcelable.Creator<IpSecAlgorithm>() {
public IpSecAlgorithm createFromParcel(Parcel in) {
- return new IpSecAlgorithm(in);
+ final String name = in.readString();
+ final byte[] key = in.createByteArray();
+ final int truncLenBits = in.readInt();
+
+ return new IpSecAlgorithm(name, key, truncLenBits);
}
public IpSecAlgorithm[] newArray(int size) {
@@ -177,30 +187,47 @@
}
};
- private IpSecAlgorithm(Parcel in) {
- mName = in.readString();
- mKey = in.createByteArray();
- mTruncLenBits = in.readInt();
- }
+ private static void checkValidOrThrow(String name, int keyLen, int truncLen) {
+ boolean isValidLen = true;
+ boolean isValidTruncLen = true;
- private static boolean isTruncationLengthValid(String algo, int truncLenBits) {
- switch (algo) {
+ switch(name) {
case CRYPT_AES_CBC:
- return (truncLenBits == 128 || truncLenBits == 192 || truncLenBits == 256);
+ isValidLen = keyLen == 128 || keyLen == 192 || keyLen == 256;
+ break;
case AUTH_HMAC_MD5:
- return (truncLenBits >= 96 && truncLenBits <= 128);
+ isValidLen = keyLen == 128;
+ isValidTruncLen = truncLen >= 96 && truncLen <= 128;
+ break;
case AUTH_HMAC_SHA1:
- return (truncLenBits >= 96 && truncLenBits <= 160);
+ isValidLen = keyLen == 160;
+ isValidTruncLen = truncLen >= 96 && truncLen <= 160;
+ break;
case AUTH_HMAC_SHA256:
- return (truncLenBits >= 96 && truncLenBits <= 256);
+ isValidLen = keyLen == 256;
+ isValidTruncLen = truncLen >= 96 && truncLen <= 256;
+ break;
case AUTH_HMAC_SHA384:
- return (truncLenBits >= 192 && truncLenBits <= 384);
+ isValidLen = keyLen == 384;
+ isValidTruncLen = truncLen >= 192 && truncLen <= 384;
+ break;
case AUTH_HMAC_SHA512:
- return (truncLenBits >= 256 && truncLenBits <= 512);
+ isValidLen = keyLen == 512;
+ isValidTruncLen = truncLen >= 256 && truncLen <= 512;
+ break;
case AUTH_CRYPT_AES_GCM:
- return (truncLenBits == 64 || truncLenBits == 96 || truncLenBits == 128);
+ // The keying material for GCM is a key plus a 32-bit salt
+ isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32;
+ break;
default:
- return false;
+ throw new IllegalArgumentException("Couldn't find an algorithm: " + name);
+ }
+
+ if (!isValidLen) {
+ throw new IllegalArgumentException("Invalid key material keyLength: " + keyLen);
+ }
+ if (!isValidTruncLen) {
+ throw new IllegalArgumentException("Invalid truncation keyLength: " + truncLen);
}
}
@@ -217,8 +244,9 @@
.toString();
}
- /** package */
- static boolean equals(IpSecAlgorithm lhs, IpSecAlgorithm rhs) {
+ /** @hide */
+ @VisibleForTesting
+ public static boolean equals(IpSecAlgorithm lhs, IpSecAlgorithm rhs) {
if (lhs == null || rhs == null) return (lhs == rhs);
return (lhs.mName.equals(rhs.mName)
&& Arrays.equals(lhs.mKey, rhs.mKey)
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index f6a69ba..3458861 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -16,95 +16,125 @@
package android.net;
+import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.BitUtils;
+import com.android.internal.util.Preconditions;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Random;
-import java.util.StringJoiner;
/**
- * Represents a mac address.
+ * Representation of a MAC address.
*
- * @hide
+ * This class only supports 48 bits long addresses and does not support 64 bits long addresses.
+ * Instances of this class are immutable.
*/
public final class MacAddress implements Parcelable {
private static final int ETHER_ADDR_LEN = 6;
private static final byte[] ETHER_ADDR_BROADCAST = addr(0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
- /** The broadcast mac address. */
- public static final MacAddress BROADCAST_ADDRESS = new MacAddress(ETHER_ADDR_BROADCAST);
+ /**
+ * The MacAddress representing the unique broadcast MAC address.
+ */
+ public static final MacAddress BROADCAST_ADDRESS = MacAddress.fromBytes(ETHER_ADDR_BROADCAST);
- /** The zero mac address. */
+ /**
+ * The MacAddress zero MAC address.
+ * @hide
+ */
public static final MacAddress ALL_ZEROS_ADDRESS = new MacAddress(0);
- /** Represents categories of mac addresses. */
- public enum MacAddressType {
- UNICAST,
- MULTICAST,
- BROADCAST;
- }
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "TYPE_" }, value = {
+ TYPE_UNKNOWN,
+ TYPE_UNICAST,
+ TYPE_MULTICAST,
+ TYPE_BROADCAST,
+ })
+ public @interface MacAddressType { }
- private static final long VALID_LONG_MASK = BROADCAST_ADDRESS.mAddr;
- private static final long LOCALLY_ASSIGNED_MASK = new MacAddress("2:0:0:0:0:0").mAddr;
- private static final long MULTICAST_MASK = new MacAddress("1:0:0:0:0:0").mAddr;
- private static final long OUI_MASK = new MacAddress("ff:ff:ff:0:0:0").mAddr;
- private static final long NIC_MASK = new MacAddress("0:0:0:ff:ff:ff").mAddr;
- private static final MacAddress BASE_ANDROID_MAC = new MacAddress("da:a1:19:0:0:0");
+ /** Indicates a MAC address of unknown type. */
+ public static final int TYPE_UNKNOWN = 0;
+ /** Indicates a MAC address is a unicast address. */
+ public static final int TYPE_UNICAST = 1;
+ /** Indicates a MAC address is a multicast address. */
+ public static final int TYPE_MULTICAST = 2;
+ /** Indicates a MAC address is the broadcast address. */
+ public static final int TYPE_BROADCAST = 3;
- // Internal representation of the mac address as a single 8 byte long.
+ private static final long VALID_LONG_MASK = (1L << 48) - 1;
+ private static final long LOCALLY_ASSIGNED_MASK = MacAddress.fromString("2:0:0:0:0:0").mAddr;
+ private static final long MULTICAST_MASK = MacAddress.fromString("1:0:0:0:0:0").mAddr;
+ private static final long OUI_MASK = MacAddress.fromString("ff:ff:ff:0:0:0").mAddr;
+ private static final long NIC_MASK = MacAddress.fromString("0:0:0:ff:ff:ff").mAddr;
+ private static final MacAddress BASE_GOOGLE_MAC = MacAddress.fromString("da:a1:19:0:0:0");
+
+ // Internal representation of the MAC address as a single 8 byte long.
// The encoding scheme sets the two most significant bytes to 0. The 6 bytes of the
- // mac address are encoded in the 6 least significant bytes of the long, where the first
+ // MAC address are encoded in the 6 least significant bytes of the long, where the first
// byte of the array is mapped to the 3rd highest logical byte of the long, the second
// byte of the array is mapped to the 4th highest logical byte of the long, and so on.
private final long mAddr;
private MacAddress(long addr) {
- mAddr = addr;
+ mAddr = (VALID_LONG_MASK & addr);
}
- /** Creates a MacAddress for the given byte representation. */
- public MacAddress(byte[] addr) {
- this(longAddrFromByteAddr(addr));
- }
-
- /** Creates a MacAddress for the given string representation. */
- public MacAddress(String addr) {
- this(longAddrFromByteAddr(byteAddrFromStringAddr(addr)));
- }
-
- /** Returns the MacAddressType of this MacAddress. */
- public MacAddressType addressType() {
+ /**
+ * Returns the type of this address.
+ *
+ * @return the int constant representing the MAC address type of this MacAddress.
+ */
+ public @MacAddressType int addressType() {
if (equals(BROADCAST_ADDRESS)) {
- return MacAddressType.BROADCAST;
+ return TYPE_BROADCAST;
}
if (isMulticastAddress()) {
- return MacAddressType.MULTICAST;
+ return TYPE_MULTICAST;
}
- return MacAddressType.UNICAST;
+ return TYPE_UNICAST;
}
- /** Returns true if this MacAddress corresponds to a multicast address. */
+ /**
+ * @return true if this MacAddress is a multicast address.
+ * @hide
+ */
public boolean isMulticastAddress() {
return (mAddr & MULTICAST_MASK) != 0;
}
- /** Returns true if this MacAddress corresponds to a locally assigned address. */
+ /**
+ * @return true if this MacAddress is a locally assigned address.
+ */
public boolean isLocallyAssigned() {
return (mAddr & LOCALLY_ASSIGNED_MASK) != 0;
}
- /** Returns a byte array representation of this MacAddress. */
+ /**
+ * @return a byte array representation of this MacAddress.
+ */
public byte[] toByteArray() {
return byteAddrFromLongAddr(mAddr);
}
@Override
public String toString() {
- return stringAddrFromByteAddr(byteAddrFromLongAddr(mAddr));
+ return stringAddrFromLongAddr(mAddr);
+ }
+
+ /**
+ * @return a String representation of the OUI part of this MacAddres,
+ * with the lower 3 bytes constituting the NIC part replaced with 0.
+ */
+ public String toSafeString() {
+ return stringAddrFromLongAddr(mAddr & OUI_MASK);
}
@Override
@@ -138,27 +168,50 @@
}
};
- /** Return true if the given byte array is not null and has the length of a mac address. */
+ /**
+ * Returns true if the given byte array is an valid MAC address.
+ * A valid byte array representation for a MacAddress is a non-null array of length 6.
+ *
+ * @param addr a byte array.
+ * @return true if the given byte array is not null and has the length of a MAC address.
+ *
+ * @hide
+ */
public static boolean isMacAddress(byte[] addr) {
return addr != null && addr.length == ETHER_ADDR_LEN;
}
/**
- * Return the MacAddressType of the mac address represented by the given byte array,
- * or null if the given byte array does not represent an mac address.
+ * Returns the MAC address type of the MAC address represented by the given byte array,
+ * or null if the given byte array does not represent a MAC address.
+ * A valid byte array representation for a MacAddress is a non-null array of length 6.
+ *
+ * @param addr a byte array representing a MAC address.
+ * @return the int constant representing the MAC address type of the MAC address represented
+ * by the given byte array, or type UNKNOWN if the byte array is not a valid MAC address.
+ *
+ * @hide
*/
- public static MacAddressType macAddressType(byte[] addr) {
+ public static int macAddressType(byte[] addr) {
if (!isMacAddress(addr)) {
- return null;
+ return TYPE_UNKNOWN;
}
- return new MacAddress(addr).addressType();
+ return MacAddress.fromBytes(addr).addressType();
}
- /** DOCME */
+ /**
+ * Converts a String representation of a MAC address to a byte array representation.
+ * A valid String representation for a MacAddress is a series of 6 values in the
+ * range [0,ff] printed in hexadecimal and joined by ':' characters.
+ *
+ * @param addr a String representation of a MAC address.
+ * @return the byte representation of the MAC address.
+ * @throws IllegalArgumentException if the given String is not a valid representation.
+ *
+ * @hide
+ */
public static byte[] byteAddrFromStringAddr(String addr) {
- if (addr == null) {
- throw new IllegalArgumentException("cannot convert the null String");
- }
+ Preconditions.checkNotNull(addr);
String[] parts = addr.split(":");
if (parts.length != ETHER_ADDR_LEN) {
throw new IllegalArgumentException(addr + " was not a valid MAC address");
@@ -174,20 +227,26 @@
return bytes;
}
- /** DOCME */
+ /**
+ * Converts a byte array representation of a MAC address to a String representation made
+ * of 6 hexadecimal numbers in [0,ff] joined by ':' characters.
+ * A valid byte array representation for a MacAddress is a non-null array of length 6.
+ *
+ * @param addr a byte array representation of a MAC address.
+ * @return the String representation of the MAC address.
+ * @throws IllegalArgumentException if the given byte array is not a valid representation.
+ *
+ * @hide
+ */
public static String stringAddrFromByteAddr(byte[] addr) {
if (!isMacAddress(addr)) {
return null;
}
- StringJoiner j = new StringJoiner(":");
- for (byte b : addr) {
- j.add(Integer.toHexString(BitUtils.uint8(b)));
- }
- return j.toString();
+ return String.format("%02x:%02x:%02x:%02x:%02x:%02x",
+ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
}
- /** @hide */
- public static byte[] byteAddrFromLongAddr(long addr) {
+ private static byte[] byteAddrFromLongAddr(long addr) {
byte[] bytes = new byte[ETHER_ADDR_LEN];
int index = ETHER_ADDR_LEN;
while (index-- > 0) {
@@ -197,8 +256,8 @@
return bytes;
}
- /** @hide */
- public static long longAddrFromByteAddr(byte[] addr) {
+ private static long longAddrFromByteAddr(byte[] addr) {
+ Preconditions.checkNotNull(addr);
if (!isMacAddress(addr)) {
throw new IllegalArgumentException(
Arrays.toString(addr) + " was not a valid MAC address");
@@ -210,19 +269,17 @@
return longAddr;
}
- /** @hide */
- public static long longAddrFromStringAddr(String addr) {
- if (addr == null) {
- throw new IllegalArgumentException("cannot convert the null String");
- }
+ // Internal conversion function equivalent to longAddrFromByteAddr(byteAddrFromStringAddr(addr))
+ // that avoids the allocation of an intermediary byte[].
+ private static long longAddrFromStringAddr(String addr) {
+ Preconditions.checkNotNull(addr);
String[] parts = addr.split(":");
if (parts.length != ETHER_ADDR_LEN) {
throw new IllegalArgumentException(addr + " was not a valid MAC address");
}
long longAddr = 0;
- int index = ETHER_ADDR_LEN;
- while (index-- > 0) {
- int x = Integer.valueOf(parts[index], 16);
+ for (int i = 0; i < parts.length; i++) {
+ int x = Integer.valueOf(parts[i], 16);
if (x < 0 || 0xff < x) {
throw new IllegalArgumentException(addr + "was not a valid MAC address");
}
@@ -231,32 +288,74 @@
return longAddr;
}
- /** @hide */
- public static String stringAddrFromLongAddr(long addr) {
- addr = Long.reverseBytes(addr) >> 16;
- StringJoiner j = new StringJoiner(":");
- for (int i = 0; i < ETHER_ADDR_LEN; i++) {
- j.add(Integer.toHexString((byte) addr));
- addr = addr >> 8;
- }
- return j.toString();
+ // Internal conversion function equivalent to stringAddrFromByteAddr(byteAddrFromLongAddr(addr))
+ // that avoids the allocation of an intermediary byte[].
+ private static String stringAddrFromLongAddr(long addr) {
+ return String.format("%02x:%02x:%02x:%02x:%02x:%02x",
+ (addr >> 40) & 0xff,
+ (addr >> 32) & 0xff,
+ (addr >> 24) & 0xff,
+ (addr >> 16) & 0xff,
+ (addr >> 8) & 0xff,
+ addr & 0xff);
}
/**
- * Returns a randomely generated mac address with the Android OUI value "DA-A1-19".
- * The locally assigned bit is always set to 1.
+ * Creates a MacAddress from the given String representation. A valid String representation
+ * for a MacAddress is a series of 6 values in the range [0,ff] printed in hexadecimal
+ * and joined by ':' characters.
+ *
+ * @param addr a String representation of a MAC address.
+ * @return the MacAddress corresponding to the given String representation.
+ * @throws IllegalArgumentException if the given String is not a valid representation.
*/
- public static MacAddress getRandomAddress() {
- return getRandomAddress(BASE_ANDROID_MAC, new Random());
+ public static MacAddress fromString(String addr) {
+ return new MacAddress(longAddrFromStringAddr(addr));
}
/**
- * Returns a randomely generated mac address using the given Random object and the same
- * OUI values as the given MacAddress. The locally assigned bit is always set to 1.
+ * Creates a MacAddress from the given byte array representation.
+ * A valid byte array representation for a MacAddress is a non-null array of length 6.
+ *
+ * @param addr a byte array representation of a MAC address.
+ * @return the MacAddress corresponding to the given byte array representation.
+ * @throws IllegalArgumentException if the given byte array is not a valid representation.
*/
- public static MacAddress getRandomAddress(MacAddress base, Random r) {
- long longAddr = (base.mAddr & OUI_MASK) | (NIC_MASK & r.nextLong()) | LOCALLY_ASSIGNED_MASK;
- return new MacAddress(longAddr);
+ public static MacAddress fromBytes(byte[] addr) {
+ return new MacAddress(longAddrFromByteAddr(addr));
+ }
+
+ /**
+ * Returns a generated MAC address whose 24 least significant bits constituting the
+ * NIC part of the address are randomly selected.
+ *
+ * The locally assigned bit is always set to 1. The multicast bit is always set to 0.
+ *
+ * @return a random locally assigned MacAddress.
+ *
+ * @hide
+ */
+ public static MacAddress createRandomUnicastAddress() {
+ return createRandomUnicastAddress(BASE_GOOGLE_MAC, new Random());
+ }
+
+ /**
+ * Returns a randomly generated MAC address using the given Random object and the same
+ * OUI values as the given MacAddress.
+ *
+ * The locally assigned bit is always set to 1. The multicast bit is always set to 0.
+ *
+ * @param base a base MacAddress whose OUI is used for generating the random address.
+ * @param r a standard Java Random object used for generating the random address.
+ * @return a random locally assigned MacAddress.
+ *
+ * @hide
+ */
+ public static MacAddress createRandomUnicastAddress(MacAddress base, Random r) {
+ long addr = (base.mAddr & OUI_MASK) | (NIC_MASK & r.nextLong());
+ addr = addr | LOCALLY_ASSIGNED_MASK;
+ addr = addr & ~MULTICAST_MASK;
+ return new MacAddress(addr);
}
// Convenience function for working around the lack of byte literals.
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index c339856..954e59c 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.app.DownloadManager;
import android.app.backup.BackupManager;
@@ -30,6 +31,8 @@
import dalvik.system.SocketTagger;
+import java.io.FileDescriptor;
+import java.io.IOException;
import java.net.DatagramSocket;
import java.net.Socket;
import java.net.SocketException;
@@ -264,14 +267,25 @@
}
/**
+ * Set specific UID to use when accounting {@link Socket} traffic
+ * originating from the current thread as the calling UID. Designed for use
+ * when another application is performing operations on your behalf.
+ * <p>
+ * Changes only take effect during subsequent calls to
+ * {@link #tagSocket(Socket)}.
+ */
+ public static void setThreadStatsUidSelf() {
+ setThreadStatsUid(android.os.Process.myUid());
+ }
+
+ /**
* Clear any active UID set to account {@link Socket} traffic originating
* from the current thread.
*
* @see #setThreadStatsUid(int)
- * @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+ @SuppressLint("Doclava125")
public static void clearThreadStatsUid() {
NetworkManagementSocketTagger.setThreadSocketStatsUid(-1);
}
@@ -316,6 +330,27 @@
}
/**
+ * Tag the given {@link FileDescriptor} socket with any statistics
+ * parameters active for the current thread. Subsequent calls always replace
+ * any existing parameters. When finished, call
+ * {@link #untagFileDescriptor(FileDescriptor)} to remove statistics
+ * parameters.
+ *
+ * @see #setThreadStatsTag(int)
+ */
+ public static void tagFileDescriptor(FileDescriptor fd) throws IOException {
+ SocketTagger.get().tag(fd);
+ }
+
+ /**
+ * Remove any statistics parameters from the given {@link FileDescriptor}
+ * socket.
+ */
+ public static void untagFileDescriptor(FileDescriptor fd) throws IOException {
+ SocketTagger.get().untag(fd);
+ }
+
+ /**
* Start profiling data usage for current UID. Only one profiling session
* can be active at a time.
*
diff --git a/core/java/android/net/metrics/WakeupStats.java b/core/java/android/net/metrics/WakeupStats.java
index 23c1f20..7277ba3 100644
--- a/core/java/android/net/metrics/WakeupStats.java
+++ b/core/java/android/net/metrics/WakeupStats.java
@@ -16,6 +16,7 @@
package android.net.metrics;
+import android.net.MacAddress;
import android.os.Process;
import android.os.SystemClock;
import android.util.SparseIntArray;
@@ -80,13 +81,13 @@
}
switch (ev.dstHwAddr.addressType()) {
- case UNICAST:
+ case MacAddress.TYPE_UNICAST:
l2UnicastCount++;
break;
- case MULTICAST:
+ case MacAddress.TYPE_MULTICAST:
l2MulticastCount++;
break;
- case BROADCAST:
+ case MacAddress.TYPE_BROADCAST:
l2BroadcastCount++;
break;
default:
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index af91e81..948d4ce 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -224,6 +224,7 @@
* - Always On Display (screen doze mode) time and power
* New in version 28:
* - Light/Deep Doze power
+ * - WiFi Multicast Wakelock statistics (count & duration)
*/
static final int CHECKIN_VERSION = 28;
@@ -313,6 +314,8 @@
private static final String CAMERA_DATA = "cam";
private static final String VIDEO_DATA = "vid";
private static final String AUDIO_DATA = "aud";
+ private static final String WIFI_MULTICAST_TOTAL_DATA = "wmct";
+ private static final String WIFI_MULTICAST_DATA = "wmc";
public static final String RESULT_RECEIVER_CONTROLLER_KEY = "controller_activity";
@@ -516,6 +519,13 @@
public abstract ArrayMap<String, ? extends Wakelock> getWakelockStats();
/**
+ * Returns the WiFi Multicast Wakelock statistics.
+ *
+ * @return a Timer Object for the per uid Multicast statistics.
+ */
+ public abstract Timer getMulticastWakelockStats();
+
+ /**
* Returns a mapping containing sync statistics.
*
* @return a Map from Strings to Timer objects.
@@ -1170,7 +1180,7 @@
public static final class PackageChange {
public String mPackageName;
public boolean mUpdate;
- public int mVersionCode;
+ public long mVersionCode;
}
public static final class DailyItem {
@@ -3363,13 +3373,16 @@
screenDozeTime / 1000);
- // Calculate wakelock times across all uids.
+ // Calculate both wakelock and wifi multicast wakelock times across all uids.
long fullWakeLockTimeTotal = 0;
long partialWakeLockTimeTotal = 0;
+ long multicastWakeLockTimeTotalMicros = 0;
+ int multicastWakeLockCountTotal = 0;
for (int iu = 0; iu < NU; iu++) {
final Uid u = uidStats.valueAt(iu);
+ // First calculating the wakelock stats
final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
= u.getWakelockStats();
for (int iw=wakelocks.size()-1; iw>=0; iw--) {
@@ -3387,6 +3400,13 @@
rawRealtime, which);
}
}
+
+ // Now calculating the wifi multicast wakelock stats
+ final Timer mcTimer = u.getMulticastWakelockStats();
+ if (mcTimer != null) {
+ multicastWakeLockTimeTotalMicros += mcTimer.getTotalTimeLocked(rawRealtime, which);
+ multicastWakeLockCountTotal += mcTimer.getCountLocked(which);
+ }
}
// Dump network stats
@@ -3502,6 +3522,11 @@
}
dumpLine(pw, 0 /* uid */, category, WIFI_SIGNAL_STRENGTH_COUNT_DATA, args);
+ // Dump Multicast total stats
+ dumpLine(pw, 0 /* uid */, category, WIFI_MULTICAST_TOTAL_DATA,
+ multicastWakeLockTimeTotalMicros / 1000,
+ multicastWakeLockCountTotal);
+
if (which == STATS_SINCE_UNPLUGGED) {
dumpLine(pw, 0 /* uid */, category, BATTERY_LEVEL_DATA, getDischargeStartLevel(),
getDischargeCurrentLevel());
@@ -3828,6 +3853,18 @@
}
}
+ // WiFi Multicast Wakelock Statistics
+ final Timer mcTimer = u.getMulticastWakelockStats();
+ if (mcTimer != null) {
+ final long totalMcWakelockTimeMs =
+ mcTimer.getTotalTimeLocked(rawRealtime, which) / 1000 ;
+ final int countMcWakelock = mcTimer.getCountLocked(which);
+ if(totalMcWakelockTimeMs > 0) {
+ dumpLine(pw, uid, category, WIFI_MULTICAST_DATA,
+ totalMcWakelockTimeMs, countMcWakelock);
+ }
+ }
+
final ArrayMap<String, ? extends Timer> syncs = u.getSyncStats();
for (int isy=syncs.size()-1; isy>=0; isy--) {
final Timer timer = syncs.valueAt(isy);
@@ -4327,15 +4364,18 @@
pw.print(" Connectivity changes: "); pw.println(connChanges);
}
- // Calculate wakelock times across all uids.
+ // Calculate both wakelock and wifi multicast wakelock times across all uids.
long fullWakeLockTimeTotalMicros = 0;
long partialWakeLockTimeTotalMicros = 0;
+ long multicastWakeLockTimeTotalMicros = 0;
+ int multicastWakeLockCountTotal = 0;
final ArrayList<TimerEntry> timers = new ArrayList<>();
for (int iu = 0; iu < NU; iu++) {
final Uid u = uidStats.valueAt(iu);
+ // First calculate wakelock statistics
final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
= u.getWakelockStats();
for (int iw=wakelocks.size()-1; iw>=0; iw--) {
@@ -4363,6 +4403,13 @@
}
}
}
+
+ // Next calculate wifi multicast wakelock statistics
+ final Timer mcTimer = u.getMulticastWakelockStats();
+ if (mcTimer != null) {
+ multicastWakeLockTimeTotalMicros += mcTimer.getTotalTimeLocked(rawRealtime, which);
+ multicastWakeLockCountTotal += mcTimer.getCountLocked(which);
+ }
}
final long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
@@ -4392,6 +4439,20 @@
pw.println(sb.toString());
}
+ if (multicastWakeLockTimeTotalMicros != 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Total WiFi Multicast wakelock Count: ");
+ sb.append(multicastWakeLockCountTotal);
+ pw.println(sb.toString());
+
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Total WiFi Multicast wakelock time: ");
+ formatTimeMsNoSpace(sb, (multicastWakeLockTimeTotalMicros + 500) / 1000);
+ pw.println(sb.toString());
+ }
+
pw.println("");
pw.print(prefix);
sb.setLength(0);
@@ -5309,6 +5370,24 @@
}
}
+ // Calculate multicast wakelock stats
+ final Timer mcTimer = u.getMulticastWakelockStats();
+ if (mcTimer != null) {
+ final long multicastWakeLockTimeMicros = mcTimer.getTotalTimeLocked(rawRealtime, which);
+ final int multicastWakeLockCount = mcTimer.getCountLocked(which);
+
+ if (multicastWakeLockTimeMicros > 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" WiFi Multicast Wakelock");
+ sb.append(" count = ");
+ sb.append(multicastWakeLockCount);
+ sb.append(" time = ");
+ formatTimeMsNoSpace(sb, (multicastWakeLockTimeMicros + 500) / 1000);
+ pw.println(sb.toString());
+ }
+ }
+
final ArrayMap<String, ? extends Timer> syncs = u.getSyncStats();
for (int isy=syncs.size()-1; isy>=0; isy--) {
final Timer timer = syncs.valueAt(isy);
@@ -7085,6 +7164,10 @@
proto.end(wToken);
}
+ // Wifi Multicast Wakelock (WIFI_MULTICAST_WAKELOCK_DATA)
+ dumpTimer(proto, UidProto.WIFI_MULTICAST_WAKELOCK, u.getMulticastWakelockStats(),
+ rawRealtimeUs, which);
+
// Wakeup alarms (WAKEUP_ALARM_DATA)
for (int ipkg = packageStats.size() - 1; ipkg >= 0; --ipkg) {
final Uid.Pkg ps = packageStats.valueAt(ipkg);
@@ -7341,6 +7424,30 @@
getLongestDeviceIdleModeTime(DEVICE_IDLE_MODE_LIGHT));
proto.end(mToken);
+ // Wifi multicast wakelock total stats (WIFI_MULTICAST_WAKELOCK_TOTAL_DATA)
+ // Calculate multicast wakelock stats across all uids.
+ long multicastWakeLockTimeTotalUs = 0;
+ int multicastWakeLockCountTotal = 0;
+
+ for (int iu = 0; iu < uidStats.size(); iu++) {
+ final Uid u = uidStats.valueAt(iu);
+
+ final Timer mcTimer = u.getMulticastWakelockStats();
+
+ if (mcTimer != null) {
+ multicastWakeLockTimeTotalUs +=
+ mcTimer.getTotalTimeLocked(rawRealtimeUs, which);
+ multicastWakeLockCountTotal += mcTimer.getCountLocked(which);
+ }
+ }
+
+ final long wmctToken = proto.start(SystemProto.WIFI_MULTICAST_WAKELOCK_TOTAL);
+ proto.write(SystemProto.WifiMulticastWakelockTotal.DURATION_MS,
+ multicastWakeLockTimeTotalUs / 1000);
+ proto.write(SystemProto.WifiMulticastWakelockTotal.COUNT,
+ multicastWakeLockCountTotal);
+ proto.end(wmctToken);
+
// Power use item (POWER_USE_ITEM_DATA)
final List<BatterySipper> sippers = helper.getUsageList();
if (sippers != null) {
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index b5bcd02..b7a4645 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -298,7 +298,7 @@
long callingIdentity = clearCallingIdentity();
Throwable throwableToPropagate = null;
try {
- action.run();
+ action.runOrThrow();
} catch (Throwable throwable) {
throwableToPropagate = throwable;
} finally {
@@ -322,7 +322,7 @@
long callingIdentity = clearCallingIdentity();
Throwable throwableToPropagate = null;
try {
- return action.get();
+ return action.getOrThrow();
} catch (Throwable throwable) {
throwableToPropagate = throwable;
return null; // overridden by throwing in finally block
@@ -778,6 +778,8 @@
private static final int LOG_MAIN_INDEX_SIZE = 8;
private static final int MAIN_INDEX_SIZE = 1 << LOG_MAIN_INDEX_SIZE;
private static final int MAIN_INDEX_MASK = MAIN_INDEX_SIZE - 1;
+ // Debuggable builds will throw an AssertionError if the number of map entries exceeds:
+ private static final int CRASH_AT_SIZE = 5_000;
/**
* We next warn when we exceed this bucket size.
@@ -899,9 +901,14 @@
keyArray[size] = key;
}
if (size >= mWarnBucketSize) {
+ final int total_size = size();
Log.v(Binder.TAG, "BinderProxy map growth! bucket size = " + size
- + " total = " + size());
+ + " total = " + total_size);
mWarnBucketSize += WARN_INCREMENT;
+ if (Build.IS_DEBUGGABLE && total_size > CRASH_AT_SIZE) {
+ throw new AssertionError("Binder ProxyMap has too many entries. "
+ + "BinderProxy leak?");
+ }
}
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 6ebf3b9..c1722d5 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -19,9 +19,11 @@
import android.Manifest;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.app.Application;
import android.content.Context;
import android.text.TextUtils;
import android.util.Slog;
+import android.view.View;
import com.android.internal.telephony.TelephonyProperties;
@@ -115,8 +117,14 @@
public static final String SERIAL = getString("no.such.thing");
/**
- * Gets the hardware serial, if available.
- * @return The serial if specified.
+ * Gets the hardware serial number, if available.
+ *
+ * <p class="note"><b>Note:</b> Root access may allow you to modify device identifiers, such as
+ * the hardware serial number. If you change these identifiers, you can use
+ * <a href="/training/articles/security-key-attestation.html">key attestation</a> to obtain
+ * proof of the device's original identifiers.
+ *
+ * @return The serial number if specified.
*/
@RequiresPermission(Manifest.permission.READ_PHONE_STATE)
public static String getSerial() {
@@ -761,6 +769,80 @@
* <p>Applications targeting this or a later release will get these
* new changes in behavior:</p>
* <ul>
+ * <li><a href="{@docRoot}about/versions/oreo/background.html">Background execution limits</a>
+ * are applied to the application.</li>
+ * <li>The behavior of AccountManager's
+ * {@link android.accounts.AccountManager#getAccountsByType},
+ * {@link android.accounts.AccountManager#getAccountsByTypeAndFeatures}, and
+ * {@link android.accounts.AccountManager#hasFeatures} has changed as documented there.</li>
+ * <li>{@link android.app.ActivityManager.RunningAppProcessInfo#IMPORTANCE_PERCEPTIBLE_PRE_26}
+ * is now returned as
+ * {@link android.app.ActivityManager.RunningAppProcessInfo#IMPORTANCE_PERCEPTIBLE}.</li>
+ * <li>The {@link android.app.NotificationManager} now requires the use of notification
+ * channels.</li>
+ * <li>Changes to the strict mode that are set in
+ * {@link Application#onCreate Application.onCreate} will no longer be clobbered after
+ * that function returns.</li>
+ * <li>A shared library apk with native code will have that native code included in
+ * the library path of its clients.</li>
+ * <li>{@link android.content.Context#getSharedPreferences Context.getSharedPreferences}
+ * in credential encrypted storage will throw an exception before the user is unlocked.</li>
+ * <li>Attempting to retrieve a {@link Context#FINGERPRINT_SERVICE} on a device that
+ * does not support that feature will now throw a runtime exception.</li>
+ * <li>{@link android.app.Fragment} will stop any active view animations when
+ * the fragment is stopped.</li>
+ * <li>Some compatibility code in Resources that attempts to use the default Theme
+ * the app may be using will be turned off, requiring the app to explicitly request
+ * resources with the right theme.</li>
+ * <li>{@link android.content.ContentResolver#notifyChange ContentResolver.notifyChange} and
+ * {@link android.content.ContentResolver#registerContentObserver
+ * ContentResolver.registerContentObserver}
+ * will throw a SecurityException if the caller does not have permission to access
+ * the provider (or the provider doesn't exit); otherwise the call will be silently
+ * ignored.</li>
+ * <li>{@link android.hardware.camera2.CameraDevice#createCaptureRequest
+ * CameraDevice.createCaptureRequest} will enable
+ * {@link android.hardware.camera2.CaptureRequest#CONTROL_ENABLE_ZSL} by default for
+ * still image capture.</li>
+ * <li>WallpaperManager's {@link android.app.WallpaperManager#getWallpaperFile},
+ * {@link android.app.WallpaperManager#getDrawable},
+ * {@link android.app.WallpaperManager#getFastDrawable},
+ * {@link android.app.WallpaperManager#peekDrawable}, and
+ * {@link android.app.WallpaperManager#peekFastDrawable} will throw an exception
+ * if you can not access the wallpaper.</li>
+ * <li>The behavior of
+ * {@link android.hardware.usb.UsbDeviceConnection#requestWait UsbDeviceConnection.requestWait}
+ * is modified as per the documentation there.</li>
+ * <li>{@link StrictMode.VmPolicy.Builder#detectAll StrictMode.VmPolicy.Builder.detectAll}
+ * will also enable {@link StrictMode.VmPolicy.Builder#detectContentUriWithoutPermission}
+ * and {@link StrictMode.VmPolicy.Builder#detectUntaggedSockets}.</li>
+ * <li>{@link StrictMode.ThreadPolicy.Builder#detectAll StrictMode.ThreadPolicy.Builder.detectAll}
+ * will also enable {@link StrictMode.ThreadPolicy.Builder#detectUnbufferedIo}.</li>
+ * <li>{@link android.provider.DocumentsContract}'s various methods will throw failure
+ * exceptions back to the caller instead of returning null.
+ * <li>{@link View#hasFocusable View.hasFocusable} now includes auto-focusable views.</li>
+ * <li>{@link android.view.SurfaceView} will no longer always change the underlying
+ * Surface object when something about it changes; apps need to look at the current
+ * state of the object to determine which things they are interested in have changed.</li>
+ * <li>{@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY} must be
+ * used for overlay windows, other system overlay window types are not allowed.</li>
+ * <li>{@link android.view.ViewTreeObserver#addOnDrawListener
+ * ViewTreeObserver.addOnDrawListener} will throw an exception if called from within
+ * onDraw.</li>
+ * <li>{@link android.graphics.Canvas#setBitmap Canvas.setBitmap} will no longer preserve
+ * the current matrix and clip stack of the canvas.</li>
+ * <li>{@link android.widget.ListPopupWindow#setHeight ListPopupWindow.setHeight}
+ * will throw an exception if a negative height is supplied.</li>
+ * <li>{@link android.widget.TextView} will use internationalized input for numbers,
+ * dates, and times.</li>
+ * <li>{@link android.widget.Toast} must be used for showing toast windows; the toast
+ * window type can not be directly used.</li>
+ * <li>{@link android.net.wifi.WifiManager#getConnectionInfo WifiManager.getConnectionInfo}
+ * requires that the caller hold the location permission to return BSSID/SSID</li>
+ * <li>{@link android.net.wifi.p2p.WifiP2pManager#requestPeers WifiP2pManager.requestPeers}
+ * requires the caller hold the location permission.</li>
+ * <li>{@link android.R.attr#maxAspectRatio} defaults to 0, meaning there is no restriction
+ * on the app's maximum aspect ratio (so it can be stretched to fill larger screens).</li>
* <li>{@link android.R.attr#focusable} defaults to a new state ({@code auto}) where it will
* inherit the value of {@link android.R.attr#clickable} unless explicitly overridden.</li>
* <li>A default theme-appropriate focus-state highlight will be supplied to all Views
@@ -772,6 +854,15 @@
/**
* O MR1.
+ *
+ * <p>Applications targeting this or a later release will get these
+ * new changes in behavior:</p>
+ * <ul>
+ * <li>Apps exporting and linking to apk shared libraries must explicitly
+ * enumerate all signing certificates in a consistent order.</li>
+ * <li>{@link android.R.attr#screenOrientation} can not be used to request a fixed
+ * orientation if the associated activity is not fullscreen and opaque.</li>
+ * </ul>
*/
public static final int O_MR1 = 27;
@@ -852,7 +943,9 @@
if (IS_ENG) return true;
if (IS_TREBLE_ENABLED) {
- int result = VintfObject.verify(new String[0]);
+ // If we can run this code, the device should already pass AVB.
+ // So, we don't need to check AVB here.
+ int result = VintfObject.verifyWithoutAvb();
if (result != 0) {
Slog.e(TAG, "Vendor interface is incompatible, error="
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index f977c1d..b1794a6 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -24,6 +24,7 @@
import android.util.Log;
import java.io.File;
+import java.util.LinkedList;
/**
* Provides access to environment variables.
@@ -291,8 +292,9 @@
}
/** {@hide} */
- public static File getReferenceProfile(String packageName) {
- return buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName);
+ public static File getProfileSnapshotPath(String packageName, String codePath) {
+ return buildPath(buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName,
+ "primary.prof.snapshot"));
}
/** {@hide} */
@@ -608,6 +610,79 @@
return false;
}
+ /** {@hide} */ public static final int HAS_MUSIC = 1 << 0;
+ /** {@hide} */ public static final int HAS_PODCASTS = 1 << 1;
+ /** {@hide} */ public static final int HAS_RINGTONES = 1 << 2;
+ /** {@hide} */ public static final int HAS_ALARMS = 1 << 3;
+ /** {@hide} */ public static final int HAS_NOTIFICATIONS = 1 << 4;
+ /** {@hide} */ public static final int HAS_PICTURES = 1 << 5;
+ /** {@hide} */ public static final int HAS_MOVIES = 1 << 6;
+ /** {@hide} */ public static final int HAS_DOWNLOADS = 1 << 7;
+ /** {@hide} */ public static final int HAS_DCIM = 1 << 8;
+ /** {@hide} */ public static final int HAS_DOCUMENTS = 1 << 9;
+
+ /** {@hide} */ public static final int HAS_ANDROID = 1 << 16;
+ /** {@hide} */ public static final int HAS_OTHER = 1 << 17;
+
+ /**
+ * Classify the content types present on the given external storage device.
+ * <p>
+ * This is typically useful for deciding if an inserted SD card is empty, or
+ * if it contains content like photos that should be preserved.
+ *
+ * @hide
+ */
+ public static int classifyExternalStorageDirectory(File dir) {
+ int res = 0;
+ for (File f : FileUtils.listFilesOrEmpty(dir)) {
+ if (f.isFile() && isInterestingFile(f)) {
+ res |= HAS_OTHER;
+ } else if (f.isDirectory() && hasInterestingFiles(f)) {
+ final String name = f.getName();
+ if (DIRECTORY_MUSIC.equals(name)) res |= HAS_MUSIC;
+ else if (DIRECTORY_PODCASTS.equals(name)) res |= HAS_PODCASTS;
+ else if (DIRECTORY_RINGTONES.equals(name)) res |= HAS_RINGTONES;
+ else if (DIRECTORY_ALARMS.equals(name)) res |= HAS_ALARMS;
+ else if (DIRECTORY_NOTIFICATIONS.equals(name)) res |= HAS_NOTIFICATIONS;
+ else if (DIRECTORY_PICTURES.equals(name)) res |= HAS_PICTURES;
+ else if (DIRECTORY_MOVIES.equals(name)) res |= HAS_MOVIES;
+ else if (DIRECTORY_DOWNLOADS.equals(name)) res |= HAS_DOWNLOADS;
+ else if (DIRECTORY_DCIM.equals(name)) res |= HAS_DCIM;
+ else if (DIRECTORY_DOCUMENTS.equals(name)) res |= HAS_DOCUMENTS;
+ else if (DIRECTORY_ANDROID.equals(name)) res |= HAS_ANDROID;
+ else res |= HAS_OTHER;
+ }
+ }
+ return res;
+ }
+
+ private static boolean hasInterestingFiles(File dir) {
+ final LinkedList<File> explore = new LinkedList<>();
+ explore.add(dir);
+ while (!explore.isEmpty()) {
+ dir = explore.pop();
+ for (File f : FileUtils.listFilesOrEmpty(dir)) {
+ if (isInterestingFile(f)) return true;
+ if (f.isDirectory()) explore.add(f);
+ }
+ }
+ return false;
+ }
+
+ private static boolean isInterestingFile(File file) {
+ if (file.isFile()) {
+ final String name = file.getName().toLowerCase();
+ if (name.endsWith(".exe") || name.equals("autorun.inf")
+ || name.equals("launchpad.zip") || name.equals(".nomedia")) {
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return false;
+ }
+ }
+
/**
* Get a top-level shared/external storage directory for placing files of a
* particular type. This is where the user will typically place and manage
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index 3314f60..1d2a408 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -56,4 +56,7 @@
/** Send a broadcast to the specified pkg and class that it should getData now. */
oneway void sendBroadcast(String pkg, String cls);
+
+ /** Tells StatsCompaionService to grab the uid map snapshot and send it to statsd. */
+ oneway void triggerUidSnapshot();
}
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index b814b46..3db12ed 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -55,12 +55,12 @@
* Inform statsd what the version and package are for each uid. Note that each array should
* have the same number of elements, and version[i] and package[i] correspond to uid[i].
*/
- oneway void informAllUidData(in int[] uid, in int[] version, in String[] app);
+ oneway void informAllUidData(in int[] uid, in long[] version, in String[] app);
/**
* Inform statsd what the uid and version are for one app that was updated.
*/
- oneway void informOnePackage(in String app, in int uid, in int version);
+ oneway void informOnePackage(in String app, in int uid, in long version);
/**
* Inform stats that an app was removed.
@@ -69,11 +69,16 @@
/**
* Fetches data for the specified configuration key. Returns a byte array representing proto
- * wire-encoded of ConfigMetricsReport.
+ * wire-encoded of ConfigMetricsReportList.
*/
byte[] getData(in String key);
/**
+ * Fetches metadata across statsd. Returns byte array representing wire-encoded proto.
+ */
+ byte[] getMetadata();
+
+ /**
* Sets a configuration with the specified config key and subscribes to updates for this
* configuration key. Broadcasts will be sent if this configuration needs to be collected.
* The configuration must be a wire-encoded StatsDConfig. The caller specifies the name of the
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 0620fa3..9c90c38 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -79,7 +79,7 @@
void setDefaultGuestRestrictions(in Bundle restrictions);
Bundle getDefaultGuestRestrictions();
boolean markGuestForDeletion(int userHandle);
- void setQuietModeEnabled(int userHandle, boolean enableQuietMode);
+ void setQuietModeEnabled(int userHandle, boolean enableQuietMode, in IntentSender target);
boolean isQuietModeEnabled(int userHandle);
boolean trySetQuietModeDisabled(int userHandle, in IntentSender target);
void setSeedAccountData(int userHandle, in String accountName,
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index d066db1..b303e10 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -109,7 +109,9 @@
// sometimes we store linked lists of these things
/*package*/ Message next;
- private static final Object sPoolSync = new Object();
+
+ /** @hide */
+ public static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
@@ -370,6 +372,12 @@
return callback;
}
+ /** @hide */
+ public Message setCallback(Runnable r) {
+ callback = r;
+ return this;
+ }
+
/**
* Obtains a Bundle of arbitrary data associated with this
* event, lazily creating it if necessary. Set this value by calling
@@ -411,6 +419,16 @@
}
/**
+ * Chainable setter for {@link #what}
+ *
+ * @hide
+ */
+ public Message setWhat(int what) {
+ this.what = what;
+ return this;
+ }
+
+ /**
* Sends this Message to the Handler specified by {@link #getTarget}.
* Throws a null pointer exception if this field has not been set.
*/
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 36121d4..62bb385 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -20,6 +20,7 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.ExceptionUtils;
import android.util.Log;
import android.util.Size;
import android.util.SizeF;
@@ -1866,7 +1867,14 @@
if (remoteStackTrace != null) {
RemoteException cause = new RemoteException(
"Remote stack trace:\n" + remoteStackTrace, null, false, false);
- e.initCause(cause);
+ try {
+ Throwable rootCause = ExceptionUtils.getRootCause(e);
+ if (rootCause != null) {
+ rootCause.initCause(cause);
+ }
+ } catch (RuntimeException ex) {
+ Log.e(TAG, "Cannot set cause " + cause + " for " + e, ex);
+ }
}
SneakyThrow.sneakyThrow(e);
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 5dd8d05..01fe5bf 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -555,6 +555,11 @@
int FORCE_ALL_APPS_STANDBY = 11;
/**
+ * Whether to enable background check on all apps or not.
+ */
+ int FORCE_BACKGROUND_CHECK = 12;
+
+ /**
* Whether to disable non-essential sensors. (e.g. edge sensors.)
*/
int OPTIONAL_SENSORS = 13;
@@ -675,6 +680,26 @@
* as the user moves between applications and doesn't require a special permission.
* </p>
*
+ * <p>
+ * Recommended naming conventions for tags to make debugging easier:
+ * <ul>
+ * <li>use a unique prefix delimited by a colon for your app/library (e.g.
+ * gmail:mytag) to make it easier to understand where the wake locks comes
+ * from. This namespace will also avoid collision for tags inside your app
+ * coming from different libraries which will make debugging easier.
+ * <li>use constants (e.g. do not include timestamps in the tag) to make it
+ * easier for tools to aggregate similar wake locks. When collecting
+ * debugging data, the platform only monitors a finite number of tags,
+ * using constants will help tools to provide better debugging data.
+ * <li>avoid using Class#getName() or similar method since this class name
+ * can be transformed by java optimizer and obfuscator tools.
+ * <li>avoid wrapping the tag or a prefix to avoid collision with wake lock
+ * tags from the platform (e.g. *alarm*).
+ * <li>never include personnally identifiable information for privacy
+ * reasons.
+ * </ul>
+ * </p>
+ *
* @param levelAndFlags Combination of wake lock level and flag values defining
* the requested behavior of the WakeLock.
* @param tag Your class name (or other tag) for debugging purposes.
@@ -1504,6 +1529,13 @@
* cost of that work can be accounted to the application.
* </p>
*
+ * <p>
+ * Make sure to follow the tag naming convention when using WorkSource
+ * to make it easier for app developers to understand wake locks
+ * attributed to them. See {@link PowerManager#newWakeLock(int, String)}
+ * documentation.
+ * </p>
+ *
* @param ws The work source, or null if none.
*/
public void setWorkSource(WorkSource ws) {
diff --git a/core/java/android/os/StatsLogEventWrapper.java b/core/java/android/os/StatsLogEventWrapper.java
index 9491bec..3ec744d 100644
--- a/core/java/android/os/StatsLogEventWrapper.java
+++ b/core/java/android/os/StatsLogEventWrapper.java
@@ -33,6 +33,8 @@
private static final int EVENT_TYPE_LIST = 3;
private static final int EVENT_TYPE_FLOAT = 4;
+ // Keep this in sync with system/core/logcat/event.logtags
+ private static final int STATS_BUFFER_TAG_ID = 1937006964;
/**
* Creates a log_event that is binary-encoded as implemented in
* system/core/liblog/log_event_list.c; this allows us to use the same parsing logic in statsd
@@ -46,9 +48,14 @@
*/
public StatsLogEventWrapper(int tag, int fields) {
// Write four bytes from tag, starting with least-significant bit.
- write4Bytes(tag);
+ // For pulled data, this tag number is not really used. We use the same tag number as
+ // pushed ones to be consistent.
+ write4Bytes(STATS_BUFFER_TAG_ID);
mStorage.write(EVENT_TYPE_LIST); // This is required to start the log entry.
mStorage.write(fields); // Indicate number of elements in this list.
+ mStorage.write(EVENT_TYPE_INT);
+ // The first element is the real atom tag number
+ write4Bytes(tag);
}
/**
diff --git a/core/java/android/os/UEventObserver.java b/core/java/android/os/UEventObserver.java
index 5c80ca6..69a3922 100644
--- a/core/java/android/os/UEventObserver.java
+++ b/core/java/android/os/UEventObserver.java
@@ -108,7 +108,7 @@
* UEventObserver after this call. Repeated calls have no effect.
*/
public final void stopObserving() {
- final UEventThread t = getThread();
+ final UEventThread t = peekThread();
if (t != null) {
t.removeObserver(this);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 22967af..61dd462 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -2115,7 +2115,7 @@
*/
public void setQuietModeEnabled(@UserIdInt int userHandle, boolean enableQuietMode) {
try {
- mService.setQuietModeEnabled(userHandle, enableQuietMode);
+ mService.setQuietModeEnabled(userHandle, enableQuietMode, null);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -2142,10 +2142,14 @@
* unlocking. If the user is already unlocked, we call through to {@link #setQuietModeEnabled}
* directly.
*
- * @return true if the quiet mode was disabled immediately
+ * @param userHandle The user that is going to disable quiet mode.
+ * @param target The target to launch when the user is unlocked.
+ * @return {@code true} if quiet mode is disabled without showing confirm credentials screen,
+ * {@code false} otherwise.
* @hide
*/
- public boolean trySetQuietModeDisabled(@UserIdInt int userHandle, IntentSender target) {
+ public boolean trySetQuietModeDisabled(
+ @UserIdInt int userHandle, @Nullable IntentSender target) {
try {
return mService.trySetQuietModeDisabled(userHandle, target);
} catch (RemoteException re) {
diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java
index 65b33e5..340f3fb 100644
--- a/core/java/android/os/VintfObject.java
+++ b/core/java/android/os/VintfObject.java
@@ -18,7 +18,6 @@
import java.util.Map;
-import android.util.Log;
/**
* Java API for libvintf.
@@ -40,7 +39,7 @@
* Verify that the given metadata for an OTA package is compatible with
* this device.
*
- * @param packageInfo a list of serialized form of HalMaanifest's /
+ * @param packageInfo a list of serialized form of HalManifest's /
* CompatibilityMatri'ces (XML).
* @return = 0 if success (compatible)
* > 0 if incompatible
@@ -48,6 +47,17 @@
*/
public static native int verify(String[] packageInfo);
+ /**
+ * Verify Vintf compatibility on the device without checking AVB
+ * (Android Verified Boot). It is useful to verify a running system
+ * image where AVB check is irrelevant.
+ *
+ * @return = 0 if success (compatible)
+ * > 0 if incompatible
+ * < 0 if any error (mount partition fails, illformed XML, etc.)
+ */
+ public static native int verifyWithoutAvb();
+
/// ---------- CTS Device Info
/**
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 2ffc7b0..3b53260 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -112,7 +112,7 @@
* path belongs to a volume managed by vold, and that path is either
* external storage data or OBB directory belonging to calling app.
*/
- int mkdirs(in String callingPkg, in String path) = 34;
+ void mkdirs(in String callingPkg, in String path) = 34;
/**
* Determines the type of the encryption password
* @return PasswordType
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 0b007dd..4796712 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1123,6 +1123,15 @@
return FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace());
}
+ /** {@hide} */
+ public void mkdirs(File file) {
+ try {
+ mStorageManager.mkdirs(mContext.getOpPackageName(), file.getAbsolutePath());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/** @removed */
public @NonNull StorageVolume[] getVolumeList() {
return getVolumeList(mContext.getUserId(), 0);
diff --git a/core/java/android/provider/AlarmClock.java b/core/java/android/provider/AlarmClock.java
index f903012..2169457 100644
--- a/core/java/android/provider/AlarmClock.java
+++ b/core/java/android/provider/AlarmClock.java
@@ -158,7 +158,6 @@
* <p>
* Dismiss all currently expired timers. If there are no expired timers, then this is a no-op.
* </p>
- * @hide
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_DISMISS_TIMER = "android.intent.action.DISMISS_TIMER";
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index a8acb97..766ad84 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -224,6 +224,12 @@
public static final int FEATURES_WIFI = 0x8;
/**
+ * Indicates the call underwent Assisted Dialing.
+ * @hide
+ */
+ public static final Integer FEATURES_ASSISTED_DIALING_USED = 0x10;
+
+ /**
* The phone number as the user entered it.
* <P>Type: TEXT</P>
*/
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index cc1c067..ec5b1c6 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -22,6 +22,7 @@
import android.annotation.SystemApi;
import android.app.Activity;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.ContentProviderClient;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
@@ -42,10 +43,12 @@
import android.graphics.Rect;
import android.net.Uri;
import android.os.RemoteException;
+import android.telecom.PhoneAccountHandle;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Pair;
import android.view.View;
+
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -4237,6 +4240,25 @@
* current carrier. An allowed bitmask of {@link #CARRIER_PRESENCE}.
*/
public static final int CARRIER_PRESENCE_VT_CAPABLE = 0x01;
+
+ /**
+ * The flattened {@link android.content.ComponentName} of a {@link
+ * android.telecom.PhoneAccountHandle} that is the preferred {@code PhoneAccountHandle} to
+ * call the contact with. Used by {@link CommonDataKinds.Phone}.
+ *
+ * @see PhoneAccountHandle#getComponentName()
+ * @see ComponentName#flattenToString()
+ */
+ String PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME = "preferred_phone_account_component_name";
+
+ /**
+ * The ID of a {@link
+ * android.telecom.PhoneAccountHandle} that is the preferred {@code PhoneAccountHandle} to
+ * call the contact with. Used by {@link CommonDataKinds.Phone}.
+ *
+ * @see PhoneAccountHandle#getId() ()
+ */
+ String PREFERRED_PHONE_ACCOUNT_ID = "preferred_phone_account_id";
}
/**
diff --git a/core/java/android/provider/SearchIndexablesContract.java b/core/java/android/provider/SearchIndexablesContract.java
index ff8b9dd..adf437c 100644
--- a/core/java/android/provider/SearchIndexablesContract.java
+++ b/core/java/android/provider/SearchIndexablesContract.java
@@ -62,11 +62,25 @@
public static final String NON_INDEXABLES_KEYS = "non_indexables_key";
/**
+ * Site map pairs data key
+ *
+ * @hide
+ */
+ public static final String SITE_MAP_PAIRS_KEYS = "site_map_pairs";
+
+ /**
* ContentProvider path for non indexable data keys.
*/
public static final String NON_INDEXABLES_KEYS_PATH = SETTINGS + "/" + NON_INDEXABLES_KEYS;
/**
+ * ContentProvider path for sitemap keys.
+ *
+ * @hide
+ */
+ public static final String SITE_MAP_PAIRS_PATH = SETTINGS + "/" + SITE_MAP_PAIRS_KEYS;
+
+ /**
* Indexable xml resources columns.
*/
public static final String[] INDEXABLES_XML_RES_COLUMNS = new String[] {
@@ -113,6 +127,18 @@
};
/**
+ * Columns for site map queries.
+ *
+ * @hide
+ */
+ public static final String[] SITE_MAP_COLUMNS = new String[] {
+ SiteMapColumns.PARENT_CLASS,
+ SiteMapColumns.PARENT_TITLE,
+ SiteMapColumns.CHILD_CLASS,
+ SiteMapColumns.CHILD_TITLE,
+ };
+
+ /**
* Indexable raw data columns indices.
*/
public static final int COLUMN_INDEX_RAW_RANK = 0;
@@ -169,6 +195,16 @@
}
/**
+ * @hide
+ */
+ public static final class SiteMapColumns {
+ public static final String PARENT_CLASS = "parent_class";
+ public static final String CHILD_CLASS = "child_class";
+ public static final String PARENT_TITLE = "parent_title";
+ public static final String CHILD_TITLE = "child_title";
+ }
+
+ /**
* Constants related to a {@link SearchIndexableData}.
*
* This is the raw data that is stored into an Index. This is related to
diff --git a/core/java/android/provider/SearchIndexablesProvider.java b/core/java/android/provider/SearchIndexablesProvider.java
index 3120e54..138e77b 100644
--- a/core/java/android/provider/SearchIndexablesProvider.java
+++ b/core/java/android/provider/SearchIndexablesProvider.java
@@ -72,6 +72,7 @@
private static final int MATCH_RES_CODE = 1;
private static final int MATCH_RAW_CODE = 2;
private static final int MATCH_NON_INDEXABLE_KEYS_CODE = 3;
+ private static final int MATCH_SITE_MAP_PAIRS_CODE = 4;
/**
* Implementation is provided by the parent class.
@@ -87,6 +88,8 @@
MATCH_RAW_CODE);
mMatcher.addURI(mAuthority, SearchIndexablesContract.NON_INDEXABLES_KEYS_PATH,
MATCH_NON_INDEXABLE_KEYS_CODE);
+ mMatcher.addURI(mAuthority, SearchIndexablesContract.SITE_MAP_PAIRS_PATH,
+ MATCH_SITE_MAP_PAIRS_CODE);
// Sanity check our setup
if (!info.exported) {
@@ -112,6 +115,8 @@
return queryRawData(null);
case MATCH_NON_INDEXABLE_KEYS_CODE:
return queryNonIndexableKeys(null);
+ case MATCH_SITE_MAP_PAIRS_CODE:
+ return querySiteMapPairs();
default:
throw new UnsupportedOperationException("Unknown Uri " + uri);
}
@@ -150,6 +155,17 @@
*/
public abstract Cursor queryNonIndexableKeys(String[] projection);
+ /**
+ * Returns a {@link Cursor}, where rows are [parent class, child class] entries to form a site
+ * map. The list of pairs should be as complete as possible.
+ *
+ * @hide
+ */
+ public Cursor querySiteMapPairs() {
+ // By default no-op.
+ return null;
+ }
+
@Override
public String getType(Uri uri) {
switch (mMatcher.match(uri)) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9945755..6b1632a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3123,6 +3123,10 @@
* to dream after a period of inactivity. This value is also known as the
* user activity timeout period since the screen isn't necessarily turned off
* when it expires.
+ *
+ * <p>
+ * This value is bounded by maximum timeout set by
+ * {@link android.app.admin.DevicePolicyManager#setMaximumTimeToLock(ComponentName, long)}.
*/
public static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
@@ -5326,11 +5330,48 @@
/**
* Experimental autofill feature.
*
- * <p>TODO(b/67867469): remove once feature is finished
+ * <p>TODO(b/67867469): document (or remove) once feature is finished
* @hide
*/
@TestApi
- public static final String AUTOFILL_FEATURE_FIELD_DETECTION = "autofill_field_detection";
+ public static final String AUTOFILL_FEATURE_FIELD_CLASSIFICATION =
+ "autofill_field_classification";
+
+ /**
+ * Experimental autofill feature.
+ *
+ * <p>TODO(b/67867469): document (or remove) once feature is finished
+ * @hide
+ */
+ public static final String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE =
+ "autofill_user_data_max_user_data_size";
+
+ /**
+ * Experimental autofill feature.
+ *
+ * <p>TODO(b/67867469): document (or remove) once feature is finished
+ * @hide
+ */
+ public static final String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE =
+ "autofill_user_data_max_field_classification_size";
+
+ /**
+ * Experimental autofill feature.
+ *
+ * <p>TODO(b/67867469): document (or remove) once feature is finished
+ * @hide
+ */
+ public static final String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH =
+ "autofill_user_data_max_value_length";
+
+ /**
+ * Experimental autofill feature.
+ *
+ * <p>TODO(b/67867469): document (or remove) once feature is finished
+ * @hide
+ */
+ public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH =
+ "autofill_user_data_min_value_length";
/**
* @deprecated Use {@link android.provider.Settings.Global#DEVICE_PROVISIONED} instead
@@ -8651,6 +8692,12 @@
"wifi_scan_always_enabled";
/**
+ * Whether soft AP will shut down after a timeout period when no devices are connected.
+ * @hide
+ */
+ public static final String SOFT_AP_TIMEOUT_ENABLED = "soft_ap_timeout_enabled";
+
+ /**
* Value to specify if Wi-Fi Wakeup feature is enabled.
*
* Type: int (0 for false, 1 for true)
@@ -9379,6 +9426,9 @@
/** {@hide} */
public static final String
BLUETOOTH_PAN_PRIORITY_PREFIX = "bluetooth_pan_priority_";
+ /** {@hide} */
+ public static final String
+ BLUETOOTH_HEARING_AID_PRIORITY_PREFIX = "bluetooth_hearing_aid_priority_";
/**
* Activity manager specific settings.
@@ -9521,8 +9571,8 @@
* The following keys are supported:
*
* <pre>
- * screen_brightness_array (string)
- * dimming_scrim_array (string)
+ * screen_brightness_array (int[])
+ * dimming_scrim_array (int[])
* prox_screen_off_delay (long)
* prox_cooldown_trigger (long)
* prox_cooldown_period (long)
@@ -9745,6 +9795,14 @@
}
/**
+ * Get the key that retrieves a bluetooth hearing aid priority.
+ * @hide
+ */
+ public static final String getBluetoothHearingAidPriorityKey(String address) {
+ return BLUETOOTH_HEARING_AID_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
+ }
+
+ /**
* Get the key that retrieves a bluetooth map priority.
* @hide
*/
@@ -10106,6 +10164,16 @@
public static final String POLICY_CONTROL = "policy_control";
/**
+ * {@link android.view.DisplayCutout DisplayCutout} emulation mode.
+ *
+ * @hide
+ */
+ public static final String EMULATE_DISPLAY_CUTOUT = "emulate_display_cutout";
+
+ /** @hide */ public static final int EMULATE_DISPLAY_CUTOUT_OFF = 0;
+ /** @hide */ public static final int EMULATE_DISPLAY_CUTOUT_ON = 1;
+
+ /**
* Defines global zen mode. ZEN_MODE_OFF, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
* or ZEN_MODE_NO_INTERRUPTIONS.
*
@@ -10419,14 +10487,6 @@
"location_settings_link_to_permissions_enabled";
/**
- * Flag to enable use of RefactoredBackupManagerService.
- *
- * @hide
- */
- public static final String BACKUP_REFACTORED_SERVICE_DISABLED =
- "backup_refactored_service_disabled";
-
- /**
* Flag to set the waiting time for euicc factory reset inside System > Settings
* Type: long
*
@@ -10445,6 +10505,15 @@
"storage_settings_clobber_threshold";
/**
+ * If set to 1, {@link Secure#LOCATION_MODE} will be set to {@link Secure#LOCATION_MODE_OFF}
+ * temporarily for all users.
+ *
+ * @hide
+ */
+ public static final String LOCATION_GLOBAL_KILL_SWITCH =
+ "location_global_kill_switch";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
@@ -10481,7 +10550,17 @@
LOW_POWER_MODE_TRIGGER_LEVEL,
BLUETOOTH_ON,
PRIVATE_DNS_MODE,
- PRIVATE_DNS_SPECIFIER
+ PRIVATE_DNS_SPECIFIER,
+ SOFT_AP_TIMEOUT_ENABLED
+ };
+
+ /**
+ * Global settings that shouldn't be persisted.
+ *
+ * @hide
+ */
+ public static final String[] TRANSIENT_SETTINGS = {
+ LOCATION_GLOBAL_KILL_SWITCH,
};
/** @hide */
@@ -11055,7 +11134,7 @@
*
* <pre>
* default (int)
- * options_array (string)
+ * options_array (int[])
* </pre>
*
* All delays in integer minutes. Array order is respected.
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 864a0fd..6be0e76 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -16,7 +16,6 @@
package android.provider;
-import android.Manifest;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
@@ -50,7 +49,7 @@
* </ul>
*
* <P> The minimum permission needed to access this content provider is
- * {@link Manifest.permission#ADD_VOICEMAIL}
+ * {@link android.Manifest.permission#ADD_VOICEMAIL}
*
* <P>Voicemails are inserted by what is called as a "voicemail source"
* application, which is responsible for syncing voicemail data between a remote
@@ -293,11 +292,26 @@
* Flag used to indicate that local, unsynced changes are present.
* Currently, this is used to indicate that the voicemail was read or deleted.
* The value will be 1 if dirty is true, 0 if false.
+ *
+ * <p>When a caller updates a voicemail row (either with {@link ContentResolver#update} or
+ * {@link ContentResolver#applyBatch}), and if the {@link ContentValues} doesn't contain
+ * this column, the voicemail provider implicitly sets it to 0 if the calling package is
+ * the {@link #SOURCE_PACKAGE} or to 1 otherwise. To prevent this behavior, explicitly set
+ * {@link #DIRTY_RETAIN} to this column in the {@link ContentValues}.
+ *
* <P>Type: INTEGER (boolean)</P>
+ *
+ * @see #DIRTY_RETAIN
*/
public static final String DIRTY = "dirty";
/**
+ * Value of {@link #DIRTY} when updating to indicate that the value should not be updated
+ * during this operation.
+ */
+ public static final int DIRTY_RETAIN = -1;
+
+ /**
* Flag used to indicate that the voicemail was deleted but not synced to the server.
* A deleted row should be ignored.
* The value will be 1 if deleted is true, 0 if false.
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.java b/core/java/android/security/keymaster/KeyAttestationPackageInfo.java
index 5a3f390..a93d1e1 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.java
+++ b/core/java/android/security/keymaster/KeyAttestationPackageInfo.java
@@ -28,7 +28,7 @@
*/
public class KeyAttestationPackageInfo implements Parcelable {
private final String mPackageName;
- private final int mPackageVersionCode;
+ private final long mPackageVersionCode;
private final Signature[] mPackageSignatures;
/**
@@ -37,7 +37,7 @@
* @param mPackageSignatures
*/
public KeyAttestationPackageInfo(
- String mPackageName, int mPackageVersionCode, Signature[] mPackageSignatures) {
+ String mPackageName, long mPackageVersionCode, Signature[] mPackageSignatures) {
super();
this.mPackageName = mPackageName;
this.mPackageVersionCode = mPackageVersionCode;
@@ -52,7 +52,7 @@
/**
* @return the mPackageVersionCode
*/
- public int getPackageVersionCode() {
+ public long getPackageVersionCode() {
return mPackageVersionCode;
}
/**
@@ -70,7 +70,7 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mPackageName);
- dest.writeInt(mPackageVersionCode);
+ dest.writeLong(mPackageVersionCode);
dest.writeTypedArray(mPackageSignatures, flags);
}
@@ -89,7 +89,7 @@
private KeyAttestationPackageInfo(Parcel source) {
mPackageName = source.readString();
- mPackageVersionCode = source.readInt();
+ mPackageVersionCode = source.readLong();
mPackageSignatures = source.createTypedArray(Signature.CREATOR);
}
}
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 953501c..1afa8b3 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -438,8 +438,27 @@
* AutofillValue password = passwordNode.getAutofillValue().getTextValue().toString();
*
* save(username, password);
- *
* </pre>
+ *
+ * <a name="Privacy"></a>
+ * <h3>Privacy</h3>
+ *
+ * <p>The {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} method is called
+ * without the user content. The Android system strips some properties of the
+ * {@link android.app.assist.AssistStructure.ViewNode view nodes} passed to these calls, but not all
+ * of them. For example, the data provided in the {@link android.view.ViewStructure.HtmlInfo}
+ * objects set by {@link android.webkit.WebView} is never stripped out.
+ *
+ * <p>Because this data could contain PII (Personally Identifiable Information, such as username or
+ * email address), the service should only use it locally (i.e., in the app's process) for
+ * heuristics purposes, but it should not be sent to external servers.
+ *
+ * <a name="FieldsClassification"></a>
+ * <h3>Metrics and fields classification</h3
+ *
+ * <p>TODO(b/67867469): document it or remove this section; in particular, document the relationship
+ * between set/getUserData(), FillResponse.setFieldClassificationIds(), and
+ * FillEventHistory.getFieldsClassification.
*/
public abstract class AutofillService extends Service {
private static final String TAG = "AutofillService";
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index cb20e71..266bcda 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -303,6 +303,10 @@
* in the constructor in a dataset that is meant to be shown to the user, the autofill UI
* for this field will not be displayed.
*
+ * <p><b>Note:</b> On Android {@link android.os.Build.VERSION_CODES#P} and
+ * higher, datasets that require authentication can be also be filtered by passing a
+ * {@link AutofillValue#forText(CharSequence) text value} as the {@code value} parameter.
+ *
* @param id id returned by {@link
* android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
* @param value value to be autofilled. Pass {@code null} if you do not have the value
@@ -320,6 +324,10 @@
* Sets the value of a field, using a custom {@link RemoteViews presentation} to
* visualize it.
*
+ * <p><b>Note:</b> On Android {@link android.os.Build.VERSION_CODES#P} and
+ * higher, datasets that require authentication can be also be filtered by passing a
+ * {@link AutofillValue#forText(CharSequence) text value} as the {@code value} parameter.
+ *
* @param id id returned by {@link
* android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
* @param value the value to be autofilled. Pass {@code null} if you do not have the value
@@ -340,12 +348,16 @@
/**
* Sets the value of a field using an <a href="#Filtering">explicit filter</a>.
*
- * <p>This method is typically used when the dataset is authenticated and the service
+ * <p>This method is typically used when the dataset requires authentication and the service
* does not know its value but wants to hide the dataset after the user enters a minimum
* number of characters. For example, if the dataset represents a credit card number and the
* service does not want to show the "Tap to authenticate" message until the user tapped
* 4 digits, in which case the filter would be {@code Pattern.compile("\\d.{4,}")}.
*
+ * <p><b>Note:</b> If the dataset requires authentication but the service knows its text
+ * value it's easier to filter by calling {@link #setValue(AutofillId, AutofillValue)} and
+ * use the value to filter.
+ *
* @param id id returned by {@link
* android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
* @param value the value to be autofilled. Pass {@code null} if you do not have the value
@@ -371,12 +383,16 @@
* Sets the value of a field, using a custom {@link RemoteViews presentation} to
* visualize it and a <a href="#Filtering">explicit filter</a>.
*
- * <p>This method is typically used when the dataset is authenticated and the service
+ * <p>This method is typically used when the dataset requires authentication and the service
* does not know its value but wants to hide the dataset after the user enters a minimum
* number of characters. For example, if the dataset represents a credit card number and the
* service does not want to show the "Tap to authenticate" message until the user tapped
* 4 digits, in which case the filter would be {@code Pattern.compile("\\d.{4,}")}.
*
+ * <p><b>Note:</b> If the dataset requires authentication but the service knows its text
+ * value it's easier to filter by calling
+ * {@link #setValue(AutofillId, AutofillValue, RemoteViews)} and using the value to filter.
+ *
* @param id id returned by {@link
* android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
* @param value the value to be autofilled. Pass {@code null} if you do not have the value
@@ -405,6 +421,7 @@
if (existingIdx >= 0) {
mFieldValues.set(existingIdx, value);
mFieldPresentations.set(existingIdx, presentation);
+ mFieldFilters.set(existingIdx, filter);
return;
}
} else {
diff --git a/core/java/android/service/autofill/EditDistanceScorer.java b/core/java/android/service/autofill/EditDistanceScorer.java
new file mode 100644
index 0000000..e25cd04
--- /dev/null
+++ b/core/java/android/service/autofill/EditDistanceScorer.java
@@ -0,0 +1,103 @@
+/*
+ * 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 android.service.autofill;
+
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.autofill.AutofillValue;
+
+/**
+ * Helper used to calculate the classification score between an actual {@link AutofillValue} filled
+ * by the user and the expected value predicted by an autofill service.
+ *
+ * TODO(b/67867469):
+ * - improve javadoc
+ * - document algorithm / copy from InternalScorer
+ * - unhide / remove testApi
+ * @hide
+ */
+@TestApi
+public final class EditDistanceScorer extends InternalScorer implements Scorer, Parcelable {
+
+ private static final EditDistanceScorer sInstance = new EditDistanceScorer();
+
+ /**
+ * Gets the singleton instance.
+ */
+ public static EditDistanceScorer getInstance() {
+ return sInstance;
+ }
+
+ private EditDistanceScorer() {
+ }
+
+ @Override
+ public float getScore(@NonNull AutofillValue actualValue, @NonNull String userData) {
+ if (actualValue == null || !actualValue.isText() || userData == null) return 0;
+ // TODO(b/67867469): implement edit distance - currently it's returning either 0, 100%, or
+ // partial match when number of chars match
+ final String textValue = actualValue.getTextValue().toString();
+ final int total = textValue.length();
+ if (total != userData.length()) return 0F;
+
+ int matches = 0;
+ for (int i = 0; i < total; i++) {
+ if (Character.toLowerCase(textValue.charAt(i)) == Character
+ .toLowerCase(userData.charAt(i))) {
+ matches++;
+ }
+ }
+
+ return ((float) matches) / total;
+ }
+
+ /////////////////////////////////////
+ // Object "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public String toString() {
+ return "EditDistanceScorer";
+ }
+
+ /////////////////////////////////////
+ // Parcelable "contract" methods. //
+ /////////////////////////////////////
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ // Do nothing
+ }
+
+ public static final Parcelable.Creator<EditDistanceScorer> CREATOR =
+ new Parcelable.Creator<EditDistanceScorer>() {
+ @Override
+ public EditDistanceScorer createFromParcel(Parcel parcel) {
+ return EditDistanceScorer.getInstance();
+ }
+
+ @Override
+ public EditDistanceScorer[] newArray(int size) {
+ return new EditDistanceScorer[size];
+ }
+ };
+}
diff --git a/core/java/android/service/autofill/FieldClassification.java b/core/java/android/service/autofill/FieldClassification.java
new file mode 100644
index 0000000..0a60208
--- /dev/null
+++ b/core/java/android/service/autofill/FieldClassification.java
@@ -0,0 +1,192 @@
+/*
+ * 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 android.service.autofill;
+
+import static android.view.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.autofill.Helper;
+
+import com.android.internal.util.Preconditions;
+
+import com.google.android.collect.Lists;
+
+import java.util.List;
+
+/**
+ * Gets the <a href="#FieldsClassification">fields classification</a> results for a given field.
+ *
+ * TODO(b/67867469):
+ * - improve javadoc
+ * - unhide / remove testApi
+ *
+ * @hide
+ */
+@TestApi
+public final class FieldClassification implements Parcelable {
+
+ private final Match mMatch;
+
+ /** @hide */
+ public FieldClassification(@NonNull Match match) {
+ mMatch = Preconditions.checkNotNull(match);
+ }
+
+ /**
+ * Gets the {@link Match matches} with the highest {@link Match#getScore() scores}.
+ *
+ * <p><b>Note:</b> There's no guarantee of how many matches will be returned. In fact,
+ * the Android System might return just the top match to minimize the impact of field
+ * classification in the device's health.
+ */
+ @NonNull
+ public List<Match> getMatches() {
+ return Lists.newArrayList(mMatch);
+ }
+
+ @Override
+ public String toString() {
+ if (!sDebug) return super.toString();
+
+ return "FieldClassification: " + mMatch;
+ }
+
+ /////////////////////////////////////
+ // Parcelable "contract" methods. //
+ /////////////////////////////////////
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeParcelable(mMatch, flags);
+ }
+
+ public static final Parcelable.Creator<FieldClassification> CREATOR =
+ new Parcelable.Creator<FieldClassification>() {
+
+ @Override
+ public FieldClassification createFromParcel(Parcel parcel) {
+ return new FieldClassification(parcel.readParcelable(null));
+ }
+
+ @Override
+ public FieldClassification[] newArray(int size) {
+ return new FieldClassification[size];
+ }
+ };
+
+ /**
+ * Gets the score of a {@link UserData} entry for the field.
+ *
+ * TODO(b/67867469):
+ * - improve javadoc
+ * - unhide / remove testApi
+ *
+ * @hide
+ */
+ @TestApi
+ public static final class Match implements Parcelable {
+
+ private final String mRemoteId;
+ private final float mScore;
+
+ /** @hide */
+ public Match(String remoteId, float score) {
+ mRemoteId = Preconditions.checkNotNull(remoteId);
+ mScore = score;
+ }
+
+ /**
+ * Gets the remote id of the {@link UserData} entry.
+ */
+ @NonNull
+ public String getRemoteId() {
+ return mRemoteId;
+ }
+
+ /**
+ * Gets a score between the value of this field and the value of the {@link UserData} entry.
+ *
+ * <p>The score is based in a case-insensitive comparisson of all characters from both the
+ * field value and the user data entry, and it ranges from {@code 0} to {@code 1000000}:
+ * <ul>
+ * <li>{@code 1.0} represents a full match ({@code 100%}).
+ * <li>{@code 0.0} represents a full mismatch ({@code 0%}).
+ * <li>Any other value is a partial match.
+ * </ul>
+ *
+ * <p>How the score is calculated depends on the algorithm used by the Android System.
+ * For example, if the user data is {@code "abc"} and the field value us {@code " abc"},
+ * the result could be:
+ * <ul>
+ * <li>{@code 1.0} if the algorithm trims the values.
+ * <li>{@code 0.0} if the algorithm compares the values sequentially.
+ * <li>{@code 0.75} if the algorithm consideres that 3/4 (75%) of the characters match.
+ * </ul>
+ *
+ * <p>Currently, the autofill service cannot configure the algorithm.
+ */
+ public float getScore() {
+ return mScore;
+ }
+
+ @Override
+ public String toString() {
+ if (!sDebug) return super.toString();
+
+ final StringBuilder string = new StringBuilder("Match: remoteId=");
+ Helper.appendRedacted(string, mRemoteId);
+ return string.append(", score=").append(mScore).toString();
+ }
+
+ /////////////////////////////////////
+ // Parcelable "contract" methods. //
+ /////////////////////////////////////
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mRemoteId);
+ parcel.writeFloat(mScore);
+ }
+
+ @SuppressWarnings("hiding")
+ public static final Parcelable.Creator<Match> CREATOR = new Parcelable.Creator<Match>() {
+
+ @Override
+ public Match createFromParcel(Parcel parcel) {
+ return new Match(parcel.readString(), parcel.readFloat());
+ }
+
+ @Override
+ public Match[] newArray(int size) {
+ return new Match[size];
+ }
+ };
+ }
+}
diff --git a/core/java/android/service/autofill/FieldsDetection.java b/core/java/android/service/autofill/FieldsDetection.java
deleted file mode 100644
index 550ecf6..0000000
--- a/core/java/android/service/autofill/FieldsDetection.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 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 android.service.autofill;
-
-import android.annotation.TestApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.view.autofill.AutofillId;
-
-/**
- * Class by service to improve autofillable fields detection by tracking the meaning of fields
- * manually edited by the user (when they match values provided by the service).
- *
- * TODO(b/67867469):
- * - proper javadoc
- * - unhide / remove testApi
- * - add FieldsDetection management so service can set it just once and reference it in further
- * calls to improve performance (and also API to refresh it)
- * - rename to FieldsDetectionInfo or FieldClassification? (same for CTS tests)
- * - add FieldsDetectionUnitTest once API is well-defined
- * @hide
- */
-@TestApi
-public final class FieldsDetection implements Parcelable {
-
- private final AutofillId mFieldId;
- private final String mRemoteId;
- private final String mValue;
-
- /**
- * Creates a field detection for just one field / value pair.
- *
- * @param fieldId autofill id of the field in the screen.
- * @param remoteId id used by the service to identify the field later.
- * @param value field value known to the service.
- *
- * TODO(b/67867469):
- * - proper javadoc
- * - change signature to allow more fields / values / match methods
- * - might also need to use a builder, where the constructor is the id for the fieldsdetector
- * - might need id for values as well
- * - add @NonNull / check it / add unit tests
- * - make 'value' input more generic so it can accept distance-based match and other matches
- * - throw exception if field value is less than X characters (somewhere between 7-10)
- * - make sure to limit total number of fields to around 10 or so
- * - use AutofillValue instead of String (so it can compare dates, for example)
- */
- public FieldsDetection(AutofillId fieldId, String remoteId, String value) {
- mFieldId = fieldId;
- mRemoteId = remoteId;
- mValue = value;
- }
-
- /** @hide */
- public AutofillId getFieldId() {
- return mFieldId;
- }
-
- /** @hide */
- public String getRemoteId() {
- return mRemoteId;
- }
-
- /** @hide */
- public String getValue() {
- return mValue;
- }
-
- /////////////////////////////////////
- // Object "contract" methods. //
- /////////////////////////////////////
- @Override
- public String toString() {
- // Cannot disclose remoteId or value because they could contain PII
- return new StringBuilder("FieldsDetection: [field=").append(mFieldId)
- .append(", remoteId_length=").append(mRemoteId.length())
- .append(", value_length=").append(mValue.length())
- .append("]").toString();
- }
-
- /////////////////////////////////////
- // Parcelable "contract" methods. //
- /////////////////////////////////////
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeParcelable(mFieldId, flags);
- parcel.writeString(mRemoteId);
- parcel.writeString(mValue);
- }
-
- public static final Parcelable.Creator<FieldsDetection> CREATOR =
- new Parcelable.Creator<FieldsDetection>() {
- @Override
- public FieldsDetection createFromParcel(Parcel parcel) {
- // TODO(b/67867469): remove comment below if it does not use a builder at the end
- // Always go through the builder to ensure the data ingested by
- // the system obeys the contract of the builder to avoid attacks
- // using specially crafted parcels.
- return new FieldsDetection(parcel.readParcelable(null), parcel.readString(),
- parcel.readString());
- }
-
- @Override
- public FieldsDetection[] newArray(int size) {
- return new FieldsDetection[size];
- }
- };
-}
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index 736d9ef..facad2d 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -16,6 +16,8 @@
package android.service.autofill;
+import static android.view.autofill.Helper.sVerbose;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -24,8 +26,10 @@
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.service.autofill.FieldClassification.Match;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
@@ -35,6 +39,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -57,10 +62,7 @@
* the history will clear out after some pre-defined time).
*/
public final class FillEventHistory implements Parcelable {
- /**
- * Not in parcel. The UID of the {@link AutofillService} that created the {@link FillResponse}.
- */
- private final int mServiceUid;
+ private static final String TAG = "FillEventHistory";
/**
* Not in parcel. The ID of the autofill session that created the {@link FillResponse}.
@@ -70,17 +72,6 @@
@Nullable private final Bundle mClientState;
@Nullable List<Event> mEvents;
- /**
- * Gets the UID of the {@link AutofillService} that created the {@link FillResponse}.
- *
- * @return The UID of the {@link AutofillService}
- *
- * @hide
- */
- public int getServiceUid() {
- return mServiceUid;
- }
-
/** @hide */
public int getSessionId() {
return mSessionId;
@@ -123,9 +114,8 @@
/**
* @hide
*/
- public FillEventHistory(int serviceUid, int sessionId, @Nullable Bundle clientState) {
+ public FillEventHistory(int sessionId, @Nullable Bundle clientState) {
mClientState = clientState;
- mServiceUid = serviceUid;
mSessionId = sessionId;
}
@@ -140,34 +130,35 @@
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeBundle(mClientState);
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeBundle(mClientState);
if (mEvents == null) {
- dest.writeInt(0);
+ parcel.writeInt(0);
} else {
- dest.writeInt(mEvents.size());
+ parcel.writeInt(mEvents.size());
int numEvents = mEvents.size();
for (int i = 0; i < numEvents; i++) {
Event event = mEvents.get(i);
- dest.writeInt(event.mEventType);
- dest.writeString(event.mDatasetId);
- dest.writeBundle(event.mClientState);
- dest.writeStringList(event.mSelectedDatasetIds);
- dest.writeArraySet(event.mIgnoredDatasetIds);
- dest.writeTypedList(event.mChangedFieldIds);
- dest.writeStringList(event.mChangedDatasetIds);
+ parcel.writeInt(event.mEventType);
+ parcel.writeString(event.mDatasetId);
+ parcel.writeBundle(event.mClientState);
+ parcel.writeStringList(event.mSelectedDatasetIds);
+ parcel.writeArraySet(event.mIgnoredDatasetIds);
+ parcel.writeTypedList(event.mChangedFieldIds);
+ parcel.writeStringList(event.mChangedDatasetIds);
- dest.writeTypedList(event.mManuallyFilledFieldIds);
+ parcel.writeTypedList(event.mManuallyFilledFieldIds);
if (event.mManuallyFilledFieldIds != null) {
final int size = event.mManuallyFilledFieldIds.size();
for (int j = 0; j < size; j++) {
- dest.writeStringList(event.mManuallyFilledDatasetIds.get(j));
+ parcel.writeStringList(event.mManuallyFilledDatasetIds.get(j));
}
}
- dest.writeString(event.mDetectedRemoteId);
- if (event.mDetectedRemoteId != null) {
- dest.writeInt(event.mDetectedFieldScore);
+ final AutofillId[] detectedFields = event.mDetectedFieldIds;
+ parcel.writeParcelableArray(detectedFields, flags);
+ if (detectedFields != null) {
+ parcel.writeParcelableArray(event.mDetectedMatches, flags);
}
}
}
@@ -259,8 +250,8 @@
@Nullable private final ArrayList<AutofillId> mManuallyFilledFieldIds;
@Nullable private final ArrayList<ArrayList<String>> mManuallyFilledDatasetIds;
- @Nullable private final String mDetectedRemoteId;
- private final int mDetectedFieldScore;
+ @Nullable private final AutofillId[] mDetectedFieldIds;
+ @Nullable private final Match[] mDetectedMatches;
/**
* Returns the type of the event.
@@ -364,35 +355,33 @@
}
/**
- * Gets the results of the last {@link FieldsDetection} request.
- *
- * @return map of edit-distance match ({@code 0} means full match,
- * {@code 1} means 1 character different, etc...) by remote id (as set in the
- * {@link FieldsDetection} constructor), or {@code null} if none of the user-input values
- * matched the requested detection.
+ * Gets the <a href="#FieldsClassification">fields classification</a> results.
*
* <p><b>Note: </b>Only set on events of type {@link #TYPE_CONTEXT_COMMITTED}, when the
- * service requested {@link FillResponse.Builder#setFieldsDetection(FieldsDetection) fields
- * detection}.
+ * service requested {@link FillResponse.Builder#setFieldClassificationIds(AutofillId...)
+ * fields classification}.
*
* TODO(b/67867469):
* - improve javadoc
- * - refine score meaning (for example, should 1 be different of -1?)
- * - mention when it's set
- * - unhide
* - unhide / remove testApi
- * - add @NonNull / check it / add unit tests
*
* @hide
*/
@TestApi
- @NonNull public Map<String, Integer> getDetectedFields() {
- if (mDetectedRemoteId == null || mDetectedFieldScore == -1) {
+ @NonNull public Map<AutofillId, FieldClassification> getFieldsClassification() {
+ if (mDetectedFieldIds == null) {
return Collections.emptyMap();
}
-
- final ArrayMap<String, Integer> map = new ArrayMap<>(1);
- map.put(mDetectedRemoteId, mDetectedFieldScore);
+ final int size = mDetectedFieldIds.length;
+ final ArrayMap<AutofillId, FieldClassification> map = new ArrayMap<>(size);
+ for (int i = 0; i < size; i++) {
+ final AutofillId id = mDetectedFieldIds[i];
+ final Match match = mDetectedMatches[i];
+ if (sVerbose) {
+ Log.v(TAG, "getFieldsClassification[" + i + "]: id=" + id + ", match=" + match);
+ }
+ map.put(id, new FieldClassification(match));
+ }
return map;
}
@@ -479,7 +468,7 @@
*
* @hide
*/
- // TODO(b/67867469): document detection field parameters once stable
+ // TODO(b/67867469): document field classification parameters once stable
public Event(int eventType, @Nullable String datasetId, @Nullable Bundle clientState,
@Nullable List<String> selectedDatasetIds,
@Nullable ArraySet<String> ignoredDatasetIds,
@@ -487,7 +476,7 @@
@Nullable ArrayList<String> changedDatasetIds,
@Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
@Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
- @Nullable String detectedRemoteId, int detectedFieldScore) {
+ @Nullable AutofillId[] detectedFieldIds, @Nullable Match[] detectedMaches) {
mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_CONTEXT_COMMITTED,
"eventType");
mDatasetId = datasetId;
@@ -510,8 +499,9 @@
}
mManuallyFilledFieldIds = manuallyFilledFieldIds;
mManuallyFilledDatasetIds = manuallyFilledDatasetIds;
- mDetectedRemoteId = detectedRemoteId;
- mDetectedFieldScore = detectedFieldScore;
+
+ mDetectedFieldIds = detectedFieldIds;
+ mDetectedMatches = detectedMaches;
}
@Override
@@ -524,8 +514,8 @@
+ ", changedDatasetsIds=" + mChangedDatasetIds
+ ", manuallyFilledFieldIds=" + mManuallyFilledFieldIds
+ ", manuallyFilledDatasetIds=" + mManuallyFilledDatasetIds
- + ", detectedRemoteId=" + mDetectedRemoteId
- + ", detectedFieldScore=" + mDetectedFieldScore
+ + ", detectedFieldIds=" + Arrays.toString(mDetectedFieldIds)
+ + ", detectedMaches =" + Arrays.toString(mDetectedMatches)
+ "]";
}
}
@@ -534,7 +524,7 @@
new Parcelable.Creator<FillEventHistory>() {
@Override
public FillEventHistory createFromParcel(Parcel parcel) {
- FillEventHistory selection = new FillEventHistory(0, 0, parcel.readBundle());
+ FillEventHistory selection = new FillEventHistory(0, parcel.readBundle());
final int numEvents = parcel.readInt();
for (int i = 0; i < numEvents; i++) {
@@ -561,15 +551,17 @@
} else {
manuallyFilledDatasetIds = null;
}
- final String detectedRemoteId = parcel.readString();
- final int detectedFieldScore = detectedRemoteId == null ? -1
- : parcel.readInt();
+ final AutofillId[] detectedFieldIds = parcel.readParcelableArray(null,
+ AutofillId.class);
+ final Match[] detectedMatches = (detectedFieldIds != null)
+ ? parcel.readParcelableArray(null, Match.class)
+ : null;
selection.addEvent(new Event(eventType, datasetId, clientState,
selectedDatasetIds, ignoredDatasets,
changedFieldIds, changedDatasetIds,
manuallyFilledFieldIds, manuallyFilledDatasetIds,
- detectedRemoteId, detectedFieldScore));
+ detectedFieldIds, detectedMatches));
}
return selection;
}
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index 84a0974..06d2b07 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -72,11 +72,13 @@
private final @Nullable SaveInfo mSaveInfo;
private final @Nullable Bundle mClientState;
private final @Nullable RemoteViews mPresentation;
+ private final @Nullable RemoteViews mHeader;
+ private final @Nullable RemoteViews mFooter;
private final @Nullable IntentSender mAuthentication;
private final @Nullable AutofillId[] mAuthenticationIds;
private final @Nullable AutofillId[] mIgnoredIds;
private final long mDisableDuration;
- private final @Nullable FieldsDetection mFieldsDetection;
+ private final @Nullable AutofillId[] mFieldClassificationIds;
private final int mFlags;
private int mRequestId;
@@ -85,11 +87,13 @@
mSaveInfo = builder.mSaveInfo;
mClientState = builder.mClientState;
mPresentation = builder.mPresentation;
+ mHeader = builder.mHeader;
+ mFooter = builder.mFooter;
mAuthentication = builder.mAuthentication;
mAuthenticationIds = builder.mAuthenticationIds;
mIgnoredIds = builder.mIgnoredIds;
mDisableDuration = builder.mDisableDuration;
- mFieldsDetection = builder.mFieldsDetection;
+ mFieldClassificationIds = builder.mFieldClassificationIds;
mFlags = builder.mFlags;
mRequestId = INVALID_REQUEST_ID;
}
@@ -115,6 +119,16 @@
}
/** @hide */
+ public @Nullable RemoteViews getHeader() {
+ return mHeader;
+ }
+
+ /** @hide */
+ public @Nullable RemoteViews getFooter() {
+ return mFooter;
+ }
+
+ /** @hide */
public @Nullable IntentSender getAuthentication() {
return mAuthentication;
}
@@ -135,8 +149,8 @@
}
/** @hide */
- public @Nullable FieldsDetection getFieldsDetection() {
- return mFieldsDetection;
+ public @Nullable AutofillId[] getFieldClassificationIds() {
+ return mFieldClassificationIds;
}
/** @hide */
@@ -171,11 +185,13 @@
private SaveInfo mSaveInfo;
private Bundle mClientState;
private RemoteViews mPresentation;
+ private RemoteViews mHeader;
+ private RemoteViews mFooter;
private IntentSender mAuthentication;
private AutofillId[] mAuthenticationIds;
private AutofillId[] mIgnoredIds;
private long mDisableDuration;
- private FieldsDetection mFieldsDetection;
+ private AutofillId[] mFieldClassificationIds;
private int mFlags;
private boolean mDestroyed;
@@ -226,16 +242,24 @@
* @param ids id of Views that when focused will display the authentication UI.
*
* @return This builder.
+
* @throws IllegalArgumentException if {@code ids} is {@code null} or empty, or if
* both {@code authentication} and {@code presentation} are {@code null}, or if
* both {@code authentication} and {@code presentation} are non-{@code null}
*
+ * @throws IllegalStateException if a {@link #setHeader(RemoteViews) header} or a
+ * {@link #setFooter(RemoteViews) footer} are already set for this builder.
+ *
* @see android.app.PendingIntent#getIntentSender()
*/
public @NonNull Builder setAuthentication(@NonNull AutofillId[] ids,
@Nullable IntentSender authentication, @Nullable RemoteViews presentation) {
throwIfDestroyed();
throwIfDisableAutofillCalled();
+ if (mHeader != null || mFooter != null) {
+ throw new IllegalStateException("Already called #setHeader() or #setFooter()");
+ }
+
if (ids == null || ids.length == 0) {
throw new IllegalArgumentException("ids cannot be null or empry");
}
@@ -329,21 +353,29 @@
}
/**
+ * Sets which fields are used for <a href="#FieldsClassification">fields classification</a>
+ *
+ * @throws IllegalArgumentException is length of {@code ids} args is more than
+ * {@link UserData#getMaxFieldClassificationIdsSize()}.
+ * @throws IllegalStateException if {@link #build()} or {@link #disableAutofill(long)} was
+ * already called.
+ * @throws NullPointerException if {@code ids} or any element on it is {@code null}.
+ *
* TODO(b/67867469):
- * - javadoc it
- * - javadoc how to check results
- * - unhide
+ * - improve javadoc: explain relationship with UserData and how to check results
* - unhide / remove testApi
- * - throw exception (and document) if response has datasets or saveinfo
- * - throw exception (and document) if id on fieldsDetection is ignored
+ * - implement multiple ids
*
* @hide
*/
@TestApi
- public Builder setFieldsDetection(@NonNull FieldsDetection fieldsDetection) {
+ public Builder setFieldClassificationIds(@NonNull AutofillId... ids) {
throwIfDestroyed();
throwIfDisableAutofillCalled();
- mFieldsDetection = Preconditions.checkNotNull(fieldsDetection);
+ Preconditions.checkArrayElementsNotNull(ids, "ids");
+ Preconditions.checkArgumentInRange(ids.length, 1,
+ UserData.getMaxFieldClassificationIdsSize(), "ids length");
+ mFieldClassificationIds = ids;
return this;
}
@@ -391,16 +423,17 @@
* @throws IllegalArgumentException if {@code duration} is not a positive number.
* @throws IllegalStateException if either {@link #addDataset(Dataset)},
* {@link #setAuthentication(AutofillId[], IntentSender, RemoteViews)},
- * {@link #setSaveInfo(SaveInfo)}, or {@link #setClientState(Bundle)}
- * was already called.
+ * {@link #setSaveInfo(SaveInfo)}, {@link #setClientState(Bundle)}, or
+ * {link #setFieldClassificationIds(AutofillId...)} was already called.
*/
+ // TODO(b/67867469): add @ to {link setFieldClassificationIds} once it's public
public Builder disableAutofill(long duration) {
throwIfDestroyed();
if (duration <= 0) {
throw new IllegalArgumentException("duration must be greater than 0");
}
if (mAuthentication != null || mDatasets != null || mSaveInfo != null
- || mFieldsDetection != null || mClientState != null) {
+ || mFieldClassificationIds != null || mClientState != null) {
throw new IllegalStateException("disableAutofill() must be the only method called");
}
@@ -409,6 +442,62 @@
}
/**
+ * Sets a header to be shown as the first element in the list of datasets.
+ *
+ * <p>When this method is called, you must also {@link #addDataset(Dataset) add a dataset},
+ * otherwise {@link #build()} throws an {@link IllegalStateException}. Similarly, this
+ * method should only be used on {@link FillResponse FillResponses} that do not require
+ * authentication (as the header could have been set directly in the main presentation in
+ * these cases).
+ *
+ * @param header a presentation to represent the header. This presentation is not clickable
+ * —calling
+ * {@link RemoteViews#setOnClickPendingIntent(int, android.app.PendingIntent)} on it would
+ * have no effect.
+ *
+ * @return this builder
+ *
+ * @throws IllegalStateException if an
+ * {@link #setAuthentication(AutofillId[], IntentSender, RemoteViews) authentication} was
+ * already set for this builder.
+ */
+ // TODO(b/69796626): make it sticky / update javadoc
+ public Builder setHeader(@NonNull RemoteViews header) {
+ throwIfDestroyed();
+ throwIfAuthenticationCalled();
+ mHeader = Preconditions.checkNotNull(header);
+ return this;
+ }
+
+ /**
+ * Sets a footer to be shown as the last element in the list of datasets.
+ *
+ * <p>When this method is called, you must also {@link #addDataset(Dataset) add a dataset},
+ * otherwise {@link #build()} throws an {@link IllegalStateException}. Similarly, this
+ * method should only be used on {@link FillResponse FillResponses} that do not require
+ * authentication (as the footer could have been set directly in the main presentation in
+ * these cases).
+ *
+ * @param footer a presentation to represent the footer. This presentation is not clickable
+ * —calling
+ * {@link RemoteViews#setOnClickPendingIntent(int, android.app.PendingIntent)} on it would
+ * have no effect.
+ *
+ * @return this builder
+ *
+ * @throws IllegalStateException if the FillResponse
+ * {@link #setAuthentication(AutofillId[], IntentSender, RemoteViews)
+ * requires authentication}.
+ */
+ // TODO(b/69796626): make it sticky / update javadoc
+ public Builder setFooter(@NonNull RemoteViews footer) {
+ throwIfDestroyed();
+ throwIfAuthenticationCalled();
+ mFooter = Preconditions.checkNotNull(footer);
+ return this;
+ }
+
+ /**
* Builds a new {@link FillResponse} instance.
*
* @throws IllegalStateException if any of the following conditions occur:
@@ -417,19 +506,28 @@
* <li>No call was made to {@link #addDataset(Dataset)},
* {@link #setAuthentication(AutofillId[], IntentSender, RemoteViews)},
* {@link #setSaveInfo(SaveInfo)}, {@link #disableAutofill(long)},
- * or {@link #setClientState(Bundle)}.
+ * {@link #setClientState(Bundle)},
+ * or {link #setFieldClassificationIds(AutofillId...)}.
+ * <li>{@link #setHeader(RemoteViews)} or {@link #setFooter(RemoteViews)} is called
+ * without any previous calls to {@link #addDataset(Dataset)}.
* </ol>
*
* @return A built response.
*/
+ // TODO(b/67867469): add @ to {link setFieldClassificationIds} once it's public
public FillResponse build() {
throwIfDestroyed();
if (mAuthentication == null && mDatasets == null && mSaveInfo == null
- && mDisableDuration == 0 && mFieldsDetection == null && mClientState == null) {
+ && mDisableDuration == 0 && mFieldClassificationIds == null
+ && mClientState == null) {
throw new IllegalStateException("need to provide: at least one DataSet, or a "
+ "SaveInfo, or an authentication with a presentation, "
+ "or a FieldsDetection, or a client state, or disable autofill");
}
+ if (mDatasets == null && (mHeader != null || mFooter != null)) {
+ throw new IllegalStateException(
+ "must add at least 1 dataset when using header or footer");
+ }
mDestroyed = true;
return new FillResponse(this);
}
@@ -445,6 +543,12 @@
throw new IllegalStateException("Already called #disableAutofill()");
}
}
+
+ private void throwIfAuthenticationCalled() {
+ if (mAuthentication != null) {
+ throw new IllegalStateException("Already called #setAuthentication()");
+ }
+ }
}
/////////////////////////////////////
@@ -461,12 +565,15 @@
.append(", saveInfo=").append(mSaveInfo)
.append(", clientState=").append(mClientState != null)
.append(", hasPresentation=").append(mPresentation != null)
+ .append(", hasHeader=").append(mHeader != null)
+ .append(", hasFooter=").append(mFooter != null)
.append(", hasAuthentication=").append(mAuthentication != null)
.append(", authenticationIds=").append(Arrays.toString(mAuthenticationIds))
.append(", ignoredIds=").append(Arrays.toString(mIgnoredIds))
.append(", disableDuration=").append(mDisableDuration)
.append(", flags=").append(mFlags)
- .append(", fieldDetection=").append(mFieldsDetection)
+ .append(", fieldClassificationIds=")
+ .append(Arrays.toString(mFieldClassificationIds))
.append("]")
.toString();
}
@@ -488,9 +595,11 @@
parcel.writeParcelableArray(mAuthenticationIds, flags);
parcel.writeParcelable(mAuthentication, flags);
parcel.writeParcelable(mPresentation, flags);
+ parcel.writeParcelable(mHeader, flags);
+ parcel.writeParcelable(mFooter, flags);
parcel.writeParcelableArray(mIgnoredIds, flags);
parcel.writeLong(mDisableDuration);
- parcel.writeParcelable(mFieldsDetection, flags);
+ parcel.writeParcelableArray(mFieldClassificationIds, flags);
parcel.writeInt(mFlags);
parcel.writeInt(mRequestId);
}
@@ -520,15 +629,24 @@
if (authenticationIds != null) {
builder.setAuthentication(authenticationIds, authentication, presentation);
}
+ final RemoteViews header = parcel.readParcelable(null);
+ if (header != null) {
+ builder.setHeader(header);
+ }
+ final RemoteViews footer = parcel.readParcelable(null);
+ if (footer != null) {
+ builder.setFooter(footer);
+ }
builder.setIgnoredIds(parcel.readParcelableArray(null, AutofillId.class));
final long disableDuration = parcel.readLong();
if (disableDuration > 0) {
builder.disableAutofill(disableDuration);
}
- final FieldsDetection fieldsDetection = parcel.readParcelable(null);
- if (fieldsDetection != null) {
- builder.setFieldsDetection(fieldsDetection);
+ final AutofillId[] fieldClassifactionIds =
+ parcel.readParcelableArray(null, AutofillId.class);
+ if (fieldClassifactionIds != null) {
+ builder.setFieldClassificationIds(fieldClassifactionIds);
}
builder.setFlags(parcel.readInt());
diff --git a/core/java/android/service/autofill/InternalScorer.java b/core/java/android/service/autofill/InternalScorer.java
new file mode 100644
index 0000000..0da5afc
--- /dev/null
+++ b/core/java/android/service/autofill/InternalScorer.java
@@ -0,0 +1,40 @@
+/*
+ * 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 android.service.autofill;
+
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.os.Parcelable;
+import android.view.autofill.AutofillValue;
+
+/**
+ * Superclass of all scorer the system understands. As this is not public all
+ * subclasses have to implement {@link Scorer} again.
+ *
+ * @hide
+ */
+@TestApi
+public abstract class InternalScorer implements Scorer, Parcelable {
+
+ /**
+ * Returns the classification score between an actual {@link AutofillValue} filled
+ * by the user and the expected value predicted by an autofill service.
+ *
+ * <p>A full-match is {@code 1.0} (representing 100%), a full mismatch is {@code 0.0} and
+ * partial mathces are something in between, typically using edit-distance algorithms.
+ */
+ public abstract float getScore(@NonNull AutofillValue actualValue, @NonNull String userData);
+}
diff --git a/core/java/android/service/autofill/NegationValidator.java b/core/java/android/service/autofill/NegationValidator.java
new file mode 100644
index 0000000..a963f9f
--- /dev/null
+++ b/core/java/android/service/autofill/NegationValidator.java
@@ -0,0 +1,79 @@
+/*
+ * 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 android.service.autofill;
+
+import static android.view.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Validator used to implement a {@code NOT} logical operation.
+ *
+ * @hide
+ */
+final class NegationValidator extends InternalValidator {
+ @NonNull private final InternalValidator mValidator;
+
+ NegationValidator(@NonNull InternalValidator validator) {
+ mValidator = Preconditions.checkNotNull(validator);
+ }
+
+ @Override
+ public boolean isValid(@NonNull ValueFinder finder) {
+ return !mValidator.isValid(finder);
+ }
+
+ /////////////////////////////////////
+ // Object "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public String toString() {
+ if (!sDebug) return super.toString();
+
+ return "NegationValidator: [validator=" + mValidator + "]";
+ }
+
+ /////////////////////////////////////
+ // Parcelable "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mValidator, flags);
+ }
+
+ public static final Parcelable.Creator<NegationValidator> CREATOR =
+ new Parcelable.Creator<NegationValidator>() {
+ @Override
+ public NegationValidator createFromParcel(Parcel parcel) {
+ return new NegationValidator(parcel.readParcelable(null));
+ }
+
+ @Override
+ public NegationValidator[] newArray(int size) {
+ return new NegationValidator[size];
+ }
+ };
+}
diff --git a/core/java/android/service/autofill/Scorer.java b/core/java/android/service/autofill/Scorer.java
new file mode 100644
index 0000000..f6a802a
--- /dev/null
+++ b/core/java/android/service/autofill/Scorer.java
@@ -0,0 +1,35 @@
+/*
+ * 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 android.service.autofill;
+
+import android.annotation.TestApi;
+
+/**
+ * Helper class used to calculate a score.
+ *
+ * <p>Typically used to calculate the field classification score between an actual
+ * {@link android.view.autofill.AutofillValue} filled by the user and the expected value predicted
+ * by an autofill service.
+ *
+ * TODO(b/67867469):
+ * - improve javadoc
+ * - unhide / remove testApi
+ * @hide
+ */
+@TestApi
+public interface Scorer {
+
+}
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/core/java/android/service/autofill/UserData.aidl
similarity index 64%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to core/java/android/service/autofill/UserData.aidl
index 4ccdea5..76016de 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/core/java/android/service/autofill/UserData.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
+/**
+ * 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
+ * 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,
@@ -14,11 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+package android.service.autofill;
-import android.telephony.SubscriptionInfo;
-
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
-}
-
+parcelable UserData;
+parcelable UserData.Constraints;
diff --git a/core/java/android/service/autofill/UserData.java b/core/java/android/service/autofill/UserData.java
new file mode 100644
index 0000000..0d37815
--- /dev/null
+++ b/core/java/android/service/autofill/UserData.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright 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 android.service.autofill;
+
+import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE;
+import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE;
+import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MAX_VALUE_LENGTH;
+import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MIN_VALUE_LENGTH;
+import static android.view.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.app.ActivityThread;
+import android.content.ContentResolver;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.autofill.Helper;
+
+import com.android.internal.util.Preconditions;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Class used by service to improve autofillable fields detection by tracking the meaning of fields
+ * manually edited by the user (when they match values provided by the service).
+ *
+ * TODO(b/67867469):
+ * - improve javadoc / add link to section on AutofillService
+ * - unhide / remove testApi
+ * @hide
+ */
+@TestApi
+public final class UserData implements Parcelable {
+
+ private static final String TAG = "UserData";
+
+ private static final int DEFAULT_MAX_USER_DATA_SIZE = 10;
+ private static final int DEFAULT_MAX_FIELD_CLASSIFICATION_IDS_SIZE = 10;
+ private static final int DEFAULT_MIN_VALUE_LENGTH = 5;
+ private static final int DEFAULT_MAX_VALUE_LENGTH = 100;
+
+ private final InternalScorer mScorer;
+ private final String[] mRemoteIds;
+ private final String[] mValues;
+
+ private UserData(Builder builder) {
+ mScorer = builder.mScorer;
+ mRemoteIds = new String[builder.mRemoteIds.size()];
+ builder.mRemoteIds.toArray(mRemoteIds);
+ mValues = new String[builder.mValues.size()];
+ builder.mValues.toArray(mValues);
+ }
+
+ /** @hide */
+ public InternalScorer getScorer() {
+ return mScorer;
+ }
+
+ /** @hide */
+ public String[] getRemoteIds() {
+ return mRemoteIds;
+ }
+
+ /** @hide */
+ public String[] getValues() {
+ return mValues;
+ }
+
+ /** @hide */
+ public void dump(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("Scorer: "); pw.println(mScorer);
+ // Cannot disclose remote ids or values because they could contain PII
+ pw.print(prefix); pw.print("Remote ids size: "); pw.println(mRemoteIds.length);
+ for (int i = 0; i < mRemoteIds.length; i++) {
+ pw.print(prefix); pw.print(prefix); pw.print(i); pw.print(": ");
+ pw.println(Helper.getRedacted(mRemoteIds[i]));
+ }
+ pw.print(prefix); pw.print("Values size: "); pw.println(mValues.length);
+ for (int i = 0; i < mValues.length; i++) {
+ pw.print(prefix); pw.print(prefix); pw.print(i); pw.print(": ");
+ pw.println(Helper.getRedacted(mValues[i]));
+ }
+ }
+
+ /** @hide */
+ public static void dumpConstraints(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("maxUserDataSize: "); pw.println(getMaxUserDataSize());
+ pw.print(prefix); pw.print("maxFieldClassificationIdsSize: ");
+ pw.println(getMaxFieldClassificationIdsSize());
+ pw.print(prefix); pw.print("minValueLength: "); pw.println(getMinValueLength());
+ pw.print(prefix); pw.print("maxValueLength: "); pw.println(getMaxValueLength());
+ }
+
+ /**
+ * A builder for {@link UserData} objects.
+ *
+ * TODO(b/67867469): unhide / remove testApi
+ *
+ * @hide
+ */
+ @TestApi
+ public static final class Builder {
+ private final InternalScorer mScorer;
+ private final ArrayList<String> mRemoteIds;
+ private final ArrayList<String> mValues;
+ private boolean mDestroyed;
+
+ /**
+ * Creates a new builder for the user data used for <a href="#FieldsClassification">fields
+ * classification</a>.
+ *
+ * @throws IllegalArgumentException if any of the following occurs:
+ * <ol>
+ * <li>{@code remoteId} is empty
+ * <li>{@code value} is empty
+ * <li>the length of {@code value} is lower than {@link UserData#getMinValueLength()}
+ * <li>the length of {@code value} is higher than {@link UserData#getMaxValueLength()}
+ * <li>{@code scorer} is not instance of a class provided by the Android System.
+ * </ol>
+ */
+ public Builder(@NonNull Scorer scorer, @NonNull String remoteId, @NonNull String value) {
+ Preconditions.checkArgument((scorer instanceof InternalScorer),
+ "not provided by Android System: " + scorer);
+ mScorer = (InternalScorer) scorer;
+ checkValidRemoteId(remoteId);
+ checkValidValue(value);
+ final int capacity = getMaxUserDataSize();
+ mRemoteIds = new ArrayList<>(capacity);
+ mValues = new ArrayList<>(capacity);
+ mRemoteIds.add(remoteId);
+ mValues.add(value);
+ }
+
+ /**
+ * Adds a new value for user data.
+ *
+ * @param remoteId unique string used to identify the user data.
+ * @param value value of the user data.
+ *
+ * @throws IllegalStateException if {@link #build()} or
+ * {@link #add(String, String)} with the same {@code remoteId} has already
+ * been called, or if the number of values add (i.e., calls made to this method plus
+ * constructor) is more than {@link UserData#getMaxUserDataSize()}.
+ *
+ * @throws IllegalArgumentException if {@code remoteId} or {@code value} are empty or if the
+ * length of {@code value} is lower than {@link UserData#getMinValueLength()}
+ * or higher than {@link UserData#getMaxValueLength()}.
+ */
+ public Builder add(@NonNull String remoteId, @NonNull String value) {
+ throwIfDestroyed();
+ checkValidRemoteId(remoteId);
+ checkValidValue(value);
+
+ Preconditions.checkState(!mRemoteIds.contains(remoteId),
+ // Don't include remoteId on message because it could contain PII
+ "already has entry with same remoteId");
+ Preconditions.checkState(!mValues.contains(value),
+ // Don't include remoteId on message because it could contain PII
+ "already has entry with same value");
+ Preconditions.checkState(mRemoteIds.size() < getMaxUserDataSize(),
+ "already added " + mRemoteIds.size() + " elements");
+ mRemoteIds.add(remoteId);
+ mValues.add(value);
+
+ return this;
+ }
+
+ private void checkValidRemoteId(@Nullable String remoteId) {
+ Preconditions.checkNotNull(remoteId);
+ Preconditions.checkArgument(!remoteId.isEmpty(), "remoteId cannot be empty");
+ }
+
+ private void checkValidValue(@Nullable String value) {
+ Preconditions.checkNotNull(value);
+ final int length = value.length();
+ Preconditions.checkArgumentInRange(length, getMinValueLength(),
+ getMaxValueLength(), "value length (" + length + ")");
+ }
+
+ /**
+ * Creates a new {@link UserData} instance.
+ *
+ * <p>You should not interact with this builder once this method is called.
+ *
+ * @throws IllegalStateException if {@link #build()} was already called.
+ *
+ * @return The built dataset.
+ */
+ public UserData build() {
+ throwIfDestroyed();
+ mDestroyed = true;
+ return new UserData(this);
+ }
+
+ private void throwIfDestroyed() {
+ if (mDestroyed) {
+ throw new IllegalStateException("Already called #build()");
+ }
+ }
+ }
+
+ /////////////////////////////////////
+ // Object "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public String toString() {
+ if (!sDebug) return super.toString();
+
+ final StringBuilder builder = new StringBuilder("UserData: [scorer=").append(mScorer);
+ // Cannot disclose remote ids or values because they could contain PII
+ builder.append(", remoteIds=");
+ Helper.appendRedacted(builder, mRemoteIds);
+ builder.append(", values=");
+ Helper.appendRedacted(builder, mValues);
+ return builder.append("]").toString();
+ }
+
+ /////////////////////////////////////
+ // Parcelable "contract" methods. //
+ /////////////////////////////////////
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeParcelable(mScorer, flags);
+ parcel.writeStringArray(mRemoteIds);
+ parcel.writeStringArray(mValues);
+ }
+
+ public static final Parcelable.Creator<UserData> CREATOR =
+ new Parcelable.Creator<UserData>() {
+ @Override
+ public UserData createFromParcel(Parcel parcel) {
+ // Always go through the builder to ensure the data ingested by
+ // the system obeys the contract of the builder to avoid attacks
+ // using specially crafted parcels.
+ final InternalScorer scorer = parcel.readParcelable(null);
+ final String[] remoteIds = parcel.readStringArray();
+ final String[] values = parcel.readStringArray();
+ final Builder builder = new Builder(scorer, remoteIds[0], values[0]);
+ for (int i = 1; i < remoteIds.length; i++) {
+ builder.add(remoteIds[i], values[i]);
+ }
+ return builder.build();
+ }
+
+ @Override
+ public UserData[] newArray(int size) {
+ return new UserData[size];
+ }
+ };
+
+ /**
+ * Gets the maximum number of values that can be added to a {@link UserData}.
+ */
+ public static int getMaxUserDataSize() {
+ return getInt(AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE, DEFAULT_MAX_USER_DATA_SIZE);
+ }
+
+ /**
+ * Gets the maximum number of ids that can be passed to {@link
+ * FillResponse.Builder#setFieldClassificationIds(android.view.autofill.AutofillId...)}.
+ */
+ public static int getMaxFieldClassificationIdsSize() {
+ return getInt(AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE,
+ DEFAULT_MAX_FIELD_CLASSIFICATION_IDS_SIZE);
+ }
+
+ /**
+ * Gets the minimum length of values passed to {@link Builder#Builder(Scorer, String, String)}.
+ */
+ public static int getMinValueLength() {
+ return getInt(AUTOFILL_USER_DATA_MIN_VALUE_LENGTH, DEFAULT_MIN_VALUE_LENGTH);
+ }
+
+ /**
+ * Gets the maximum length of values passed to {@link Builder#Builder(Scorer, String, String)}.
+ */
+ public static int getMaxValueLength() {
+ return getInt(AUTOFILL_USER_DATA_MAX_VALUE_LENGTH, DEFAULT_MAX_VALUE_LENGTH);
+ }
+
+ private static int getInt(String settings, int defaultValue) {
+ ContentResolver cr = null;
+ final ActivityThread at = ActivityThread.currentActivityThread();
+ if (at != null) {
+ cr = at.getApplication().getContentResolver();
+ }
+
+ if (cr == null) {
+ Log.w(TAG, "Could not read from " + settings + "; hardcoding " + defaultValue);
+ return defaultValue;
+ }
+ return Settings.Secure.getInt(cr, settings, defaultValue);
+ }
+}
diff --git a/core/java/android/service/autofill/Validators.java b/core/java/android/service/autofill/Validators.java
index 51b503c..1c83868 100644
--- a/core/java/android/service/autofill/Validators.java
+++ b/core/java/android/service/autofill/Validators.java
@@ -52,6 +52,19 @@
return new OptionalValidators(getInternalValidators(validators));
}
+ /**
+ * Creates a validator that is valid only if {@code validator} is not.
+ *
+ * @throws IllegalArgumentException if {@code validator} is an instance of a class that is not
+ * provided by the Android System.
+ */
+ @NonNull
+ public static Validator not(@NonNull Validator validator) {
+ Preconditions.checkArgument(validator instanceof InternalValidator,
+ "validator not provided by Android System: " + validator);
+ return new NegationValidator((InternalValidator) validator);
+ }
+
private static InternalValidator[] getInternalValidators(Validator[] validators) {
Preconditions.checkArrayElementsNotNull(validators, "validators");
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index cd233b8..df0842f 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -105,6 +105,13 @@
public static final String EXTRA_RESOLUTION_CALLING_PACKAGE =
"android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE";
+ /**
+ * Intent extra set for resolution requests containing a boolean indicating whether to ask the
+ * user to retry another confirmation code.
+ */
+ public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED =
+ "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED";
+
/** Result code for a successful operation. */
public static final int RESULT_OK = 0;
/** Result code indicating that an active SIM must be deactivated to perform the operation. */
diff --git a/services/core/java/com/android/server/notification/ScheduleCalendar.java b/core/java/android/service/notification/ScheduleCalendar.java
similarity index 64%
rename from services/core/java/com/android/server/notification/ScheduleCalendar.java
rename to core/java/android/service/notification/ScheduleCalendar.java
index 40230bd..8a7ff4d 100644
--- a/services/core/java/com/android/server/notification/ScheduleCalendar.java
+++ b/core/java/android/service/notification/ScheduleCalendar.java
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
+/*
+ * 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
+ * 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,
@@ -14,16 +14,22 @@
* limitations under the License.
*/
-package com.android.server.notification;
+package android.service.notification;
import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.util.ArraySet;
+import android.util.Log;
import java.util.Calendar;
import java.util.Objects;
import java.util.TimeZone;
+/**
+ * @hide
+ */
public class ScheduleCalendar {
+ public static final String TAG = "ScheduleCalendar";
+ public static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG);
private final ArraySet<Integer> mDays = new ArraySet<Integer>();
private final Calendar mCalendar = Calendar.getInstance();
@@ -34,25 +40,63 @@
return "ScheduleCalendar[mDays=" + mDays + ", mSchedule=" + mSchedule + "]";
}
+ /**
+ * @return true if schedule will exit on alarm, else false
+ */
+ public boolean exitAtAlarm() {
+ return mSchedule.exitAtAlarm;
+ }
+
+ /**
+ * Sets schedule information
+ */
public void setSchedule(ScheduleInfo schedule) {
if (Objects.equals(mSchedule, schedule)) return;
mSchedule = schedule;
updateDays();
}
+ /**
+ * Sets next alarm of the schedule if the saved next alarm has passed or is further
+ * in the future than given nextAlarm
+ * @param now current time in milliseconds
+ * @param nextAlarm time of next alarm in milliseconds
+ */
public void maybeSetNextAlarm(long now, long nextAlarm) {
- if (mSchedule != null) {
- if (mSchedule.exitAtAlarm
- && (now > mSchedule.nextAlarm || nextAlarm < mSchedule.nextAlarm)) {
- mSchedule.nextAlarm = nextAlarm;
+ if (mSchedule != null && mSchedule.exitAtAlarm) {
+ // alarm canceled
+ if (nextAlarm == 0) {
+ mSchedule.nextAlarm = 0;
+ }
+ // only allow alarms in the future
+ if (nextAlarm > now) {
+ // store earliest alarm
+ if (mSchedule.nextAlarm == 0) {
+ mSchedule.nextAlarm = nextAlarm;
+ } else {
+ mSchedule.nextAlarm = Math.min(mSchedule.nextAlarm, nextAlarm);
+ }
+ } else if (mSchedule.nextAlarm < now) {
+ if (DEBUG) {
+ Log.d(TAG, "All alarms are in the past " + mSchedule.nextAlarm);
+ }
+ mSchedule.nextAlarm = 0;
}
}
}
+ /**
+ * Set calendar time zone to tz
+ * @param tz current time zone
+ */
public void setTimeZone(TimeZone tz) {
mCalendar.setTimeZone(tz);
}
+ /**
+ * @param now current time in milliseconds
+ * @return next time this rule changes (starts or ends)
+ */
public long getNextChangeTime(long now) {
if (mSchedule == null) return 0;
final long nextStart = getNextTime(now, mSchedule.startHour, mSchedule.startMinute);
@@ -76,6 +120,10 @@
return mCalendar.getTimeInMillis();
}
+ /**
+ * @param time milliseconds since Epoch
+ * @return true if time is within the schedule, else false
+ */
public boolean isInSchedule(long time) {
if (mSchedule == null || mDays.size() == 0) return false;
final long start = getTime(time, mSchedule.startHour, mSchedule.startMinute);
@@ -86,7 +134,14 @@
return isInSchedule(-1, time, start, end) || isInSchedule(0, time, start, end);
}
+ /**
+ * @param time milliseconds since Epoch
+ * @return true if should exit at time for next alarm, else false
+ */
public boolean shouldExitForAlarm(long time) {
+ if (mSchedule == null) {
+ return false;
+ }
return mSchedule.exitAtAlarm
&& mSchedule.nextAlarm != 0
&& time >= mSchedule.nextAlarm;
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 735b822..f658ae0 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -46,8 +46,10 @@
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
+import java.util.List;
import java.util.Locale;
import java.util.Objects;
+import java.util.TimeZone;
import java.util.UUID;
/**
@@ -64,11 +66,13 @@
public static final int MAX_SOURCE = SOURCE_STAR;
private static final int DEFAULT_SOURCE = SOURCE_CONTACT;
+ public static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE";
+ public static final String EVERY_NIGHT_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE";
+ public static final List<String> DEFAULT_RULE_IDS = Arrays.asList(EVERY_NIGHT_DEFAULT_RULE_ID,
+ EVENTS_DEFAULT_RULE_ID);
+
public static final int[] ALL_DAYS = { Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY,
Calendar.WEDNESDAY, Calendar.THURSDAY, Calendar.FRIDAY, Calendar.SATURDAY };
- public static final int[] WEEKNIGHT_DAYS = { Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY,
- Calendar.WEDNESDAY, Calendar.THURSDAY };
- public static final int[] WEEKEND_DAYS = { Calendar.FRIDAY, Calendar.SATURDAY };
public static final int[] MINUTE_BUCKETS = generateMinuteBuckets();
private static final int SECONDS_MS = 1000;
@@ -529,6 +533,13 @@
rt.creationTime = safeLong(parser, RULE_ATT_CREATION_TIME, 0);
rt.enabler = parser.getAttributeValue(null, RULE_ATT_ENABLER);
rt.condition = readConditionXml(parser);
+
+ // all default rules and user created rules updated to zenMode important interruptions
+ if (rt.zenMode != Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ && Condition.isValidId(rt.conditionId, SYSTEM_AUTHORITY)) {
+ Slog.i(TAG, "Updating zenMode of automatic rule " + rt.name);
+ rt.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ }
return rt;
}
@@ -692,6 +703,20 @@
suppressedVisualEffects);
}
+ /**
+ * Creates scheduleCalendar from a condition id
+ * @param conditionId
+ * @return ScheduleCalendar with info populated with conditionId
+ */
+ public static ScheduleCalendar toScheduleCalendar(Uri conditionId) {
+ final ScheduleInfo schedule = ZenModeConfig.tryParseScheduleConditionId(conditionId);
+ if (schedule == null || schedule.days == null || schedule.days.length == 0) return null;
+ final ScheduleCalendar sc = new ScheduleCalendar();
+ sc.setSchedule(schedule);
+ sc.setTimeZone(TimeZone.getDefault());
+ return sc;
+ }
+
private static int sourceToPrioritySenders(int source, int def) {
switch (source) {
case SOURCE_ANYONE: return Policy.PRIORITY_SENDERS_ANY;
@@ -793,7 +818,10 @@
Condition.FLAG_RELEVANT_NOW);
}
- private static CharSequence getFormattedTime(Context context, long time, boolean isSameDay,
+ /**
+ * Creates readable time from time in milliseconds
+ */
+ public static CharSequence getFormattedTime(Context context, long time, boolean isSameDay,
int userHandle) {
String skeleton = (!isSameDay ? "EEE " : "")
+ (DateFormat.is24HourFormat(context, userHandle) ? "Hm" : "hma");
@@ -801,7 +829,10 @@
return DateFormat.format(pattern, time);
}
- private static boolean isToday(long time) {
+ /**
+ * Determines whether a time in milliseconds is today or not
+ */
+ public static boolean isToday(long time) {
GregorianCalendar now = new GregorianCalendar();
GregorianCalendar endTime = new GregorianCalendar();
endTime.setTimeInMillis(time);
@@ -890,7 +921,17 @@
}
public static boolean isValidScheduleConditionId(Uri conditionId) {
- return tryParseScheduleConditionId(conditionId) != null;
+ ScheduleInfo info;
+ try {
+ info = tryParseScheduleConditionId(conditionId);
+ } catch (NullPointerException | ArrayIndexOutOfBoundsException e) {
+ return false;
+ }
+
+ if (info == null || info.days == null || info.days.length == 0) {
+ return false;
+ }
+ return true;
}
public static ScheduleInfo tryParseScheduleConditionId(Uri conditionId) {
@@ -1071,7 +1112,10 @@
return UUID.randomUUID().toString().replace("-", "");
}
- private static String getOwnerCaption(Context context, String owner) {
+ /**
+ * Gets the name of the app associated with owner
+ */
+ public static String getOwnerCaption(Context context, String owner) {
final PackageManager pm = context.getPackageManager();
try {
final ApplicationInfo info = pm.getApplicationInfo(owner, 0);
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
index 7285fb4..f7acfc5 100644
--- a/core/java/android/service/vr/IVrManager.aidl
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -17,6 +17,7 @@
package android.service.vr;
import android.app.Vr2dDisplayProperties;
+import android.content.ComponentName;
import android.service.vr.IVrStateCallbacks;
import android.service.vr.IPersistentVrStateCallbacks;
@@ -109,5 +110,13 @@
* @param standy True if the device is entering standby, false if it's exiting standby.
*/
void setStandbyEnabled(boolean standby);
+
+ /**
+ * Start VR Input method for the given packageName in {@param componentName}.
+ * This method notifies InputMethodManagerService to use VR IME instead of
+ * regular phone IME.
+ */
+ void setVrInputMethod(in ComponentName componentName);
+
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 1c6275f..e5ab3e1 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -42,6 +42,7 @@
import android.util.Log;
import android.util.MergedConfiguration;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.Gravity;
import android.view.IWindowSession;
import android.view.InputChannel;
@@ -176,6 +177,9 @@
final Rect mFinalSystemInsets = new Rect();
final Rect mFinalStableInsets = new Rect();
final Rect mBackdropFrame = new Rect();
+ final DisplayCutout.ParcelableWrapper mDisplayCutout =
+ new DisplayCutout.ParcelableWrapper();
+ DisplayCutout mDispatchedDisplayCutout = DisplayCutout.NO_CUTOUT;
final MergedConfiguration mMergedConfiguration = new MergedConfiguration();
final WindowManager.LayoutParams mLayout
@@ -302,7 +306,8 @@
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, Rect backDropRect, boolean forceLayout,
- boolean alwaysConsumeNavBar, int displayId) {
+ boolean alwaysConsumeNavBar, int displayId,
+ DisplayCutout.ParcelableWrapper displayCutout) {
Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
reportDraw ? 1 : 0, outsets);
mCaller.sendMessage(msg);
@@ -750,7 +755,7 @@
mInputChannel = new InputChannel();
if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE,
Display.DEFAULT_DISPLAY, mContentInsets, mStableInsets, mOutsets,
- mInputChannel) < 0) {
+ mDisplayCutout, mInputChannel) < 0) {
Log.w(TAG, "Failed to add window while updating wallpaper surface.");
return;
}
@@ -776,7 +781,7 @@
mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets,
mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame,
- mMergedConfiguration, mSurfaceHolder.mSurface);
+ mDisplayCutout, mMergedConfiguration, mSurfaceHolder.mSurface);
if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
+ ", frame=" + mWinFrame);
@@ -800,6 +805,8 @@
mStableInsets.top += padding.top;
mStableInsets.right += padding.right;
mStableInsets.bottom += padding.bottom;
+ mDisplayCutout.set(mDisplayCutout.get().inset(-padding.left, -padding.top,
+ -padding.right, -padding.bottom));
}
if (mCurWidth != w) {
@@ -819,6 +826,7 @@
insetsChanged |= !mDispatchedContentInsets.equals(mContentInsets);
insetsChanged |= !mDispatchedStableInsets.equals(mStableInsets);
insetsChanged |= !mDispatchedOutsets.equals(mOutsets);
+ insetsChanged |= !mDispatchedDisplayCutout.equals(mDisplayCutout.get());
mSurfaceHolder.setSurfaceFrameSize(w, h);
mSurfaceHolder.mSurfaceLock.unlock();
@@ -885,11 +893,13 @@
mDispatchedContentInsets.set(mContentInsets);
mDispatchedStableInsets.set(mStableInsets);
mDispatchedOutsets.set(mOutsets);
+ mDispatchedDisplayCutout = mDisplayCutout.get();
mFinalSystemInsets.set(mDispatchedOverscanInsets);
mFinalStableInsets.set(mDispatchedStableInsets);
WindowInsets insets = new WindowInsets(mFinalSystemInsets,
null, mFinalStableInsets,
- getResources().getConfiguration().isScreenRound(), false);
+ getResources().getConfiguration().isScreenRound(), false,
+ mDispatchedDisplayCutout);
if (DEBUG) {
Log.v(TAG, "dispatching insets=" + insets);
}
diff --git a/core/java/android/text/AutoGrowArray.java b/core/java/android/text/AutoGrowArray.java
new file mode 100644
index 0000000..e428377
--- /dev/null
+++ b/core/java/android/text/AutoGrowArray.java
@@ -0,0 +1,374 @@
+/*
+ * 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 android.text;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+
+import com.android.internal.util.ArrayUtils;
+
+import libcore.util.EmptyArray;
+
+/**
+ * Implements a growing array of int primitives.
+ *
+ * These arrays are NOT thread safe.
+ *
+ * @hide
+ */
+public final class AutoGrowArray {
+ private static final int MIN_CAPACITY_INCREMENT = 12;
+ private static final int MAX_CAPACITY_TO_BE_KEPT = 10000;
+
+ /**
+ * Returns next capacity size.
+ *
+ * The returned capacity is larger than requested capacity.
+ */
+ private static int computeNewCapacity(int currentSize, int requested) {
+ final int targetCapacity = currentSize + (currentSize < (MIN_CAPACITY_INCREMENT / 2)
+ ? MIN_CAPACITY_INCREMENT : currentSize >> 1);
+ return targetCapacity > requested ? targetCapacity : requested;
+ }
+
+ /**
+ * An auto growing byte array.
+ */
+ public static class ByteArray {
+
+ private @NonNull byte[] mValues;
+ private @IntRange(from = 0) int mSize;
+
+ /**
+ * Creates an empty ByteArray with the default initial capacity.
+ */
+ public ByteArray() {
+ this(10);
+ }
+
+ /**
+ * Creates an empty ByteArray with the specified initial capacity.
+ */
+ public ByteArray(@IntRange(from = 0) int initialCapacity) {
+ if (initialCapacity == 0) {
+ mValues = EmptyArray.BYTE;
+ } else {
+ mValues = ArrayUtils.newUnpaddedByteArray(initialCapacity);
+ }
+ mSize = 0;
+ }
+
+ /**
+ * Changes the size of this ByteArray. If this ByteArray is shrinked, the backing array
+ * capacity is unchanged.
+ */
+ public void resize(@IntRange(from = 0) int newSize) {
+ if (newSize > mValues.length) {
+ ensureCapacity(newSize - mSize);
+ }
+ mSize = newSize;
+ }
+
+ /**
+ * Appends the specified value to the end of this array.
+ */
+ public void append(byte value) {
+ ensureCapacity(1);
+ mValues[mSize++] = value;
+ }
+
+ /**
+ * Ensures capacity to append at least <code>count</code> values.
+ */
+ private void ensureCapacity(@IntRange int count) {
+ final int requestedSize = mSize + count;
+ if (requestedSize >= mValues.length) {
+ final int newCapacity = computeNewCapacity(mSize, requestedSize);
+ final byte[] newValues = ArrayUtils.newUnpaddedByteArray(newCapacity);
+ System.arraycopy(mValues, 0, newValues, 0, mSize);
+ mValues = newValues;
+ }
+ }
+
+ /**
+ * Removes all values from this array.
+ */
+ public void clear() {
+ mSize = 0;
+ }
+
+ /**
+ * Removes all values from this array and release the internal array object if it is too
+ * large.
+ */
+ public void clearWithReleasingLargeArray() {
+ clear();
+ if (mValues.length > MAX_CAPACITY_TO_BE_KEPT) {
+ mValues = EmptyArray.BYTE;
+ }
+ }
+
+ /**
+ * Returns the value at the specified position in this array.
+ */
+ public byte get(@IntRange(from = 0) int index) {
+ return mValues[index];
+ }
+
+ /**
+ * Sets the value at the specified position in this array.
+ */
+ public void set(@IntRange(from = 0) int index, byte value) {
+ mValues[index] = value;
+ }
+
+ /**
+ * Returns the number of values in this array.
+ */
+ public @IntRange(from = 0) int size() {
+ return mSize;
+ }
+
+ /**
+ * Returns internal raw array.
+ *
+ * Note that this array may have larger size than you requested.
+ * Use size() instead for getting the actual array size.
+ */
+ public @NonNull byte[] getRawArray() {
+ return mValues;
+ }
+ }
+
+ /**
+ * An auto growing int array.
+ */
+ public static class IntArray {
+
+ private @NonNull int[] mValues;
+ private @IntRange(from = 0) int mSize;
+
+ /**
+ * Creates an empty IntArray with the default initial capacity.
+ */
+ public IntArray() {
+ this(10);
+ }
+
+ /**
+ * Creates an empty IntArray with the specified initial capacity.
+ */
+ public IntArray(@IntRange(from = 0) int initialCapacity) {
+ if (initialCapacity == 0) {
+ mValues = EmptyArray.INT;
+ } else {
+ mValues = ArrayUtils.newUnpaddedIntArray(initialCapacity);
+ }
+ mSize = 0;
+ }
+
+ /**
+ * Changes the size of this IntArray. If this IntArray is shrinked, the backing array
+ * capacity is unchanged.
+ */
+ public void resize(@IntRange(from = 0) int newSize) {
+ if (newSize > mValues.length) {
+ ensureCapacity(newSize - mSize);
+ }
+ mSize = newSize;
+ }
+
+ /**
+ * Appends the specified value to the end of this array.
+ */
+ public void append(int value) {
+ ensureCapacity(1);
+ mValues[mSize++] = value;
+ }
+
+ /**
+ * Ensures capacity to append at least <code>count</code> values.
+ */
+ private void ensureCapacity(@IntRange(from = 0) int count) {
+ final int requestedSize = mSize + count;
+ if (requestedSize >= mValues.length) {
+ final int newCapacity = computeNewCapacity(mSize, requestedSize);
+ final int[] newValues = ArrayUtils.newUnpaddedIntArray(newCapacity);
+ System.arraycopy(mValues, 0, newValues, 0, mSize);
+ mValues = newValues;
+ }
+ }
+
+ /**
+ * Removes all values from this array.
+ */
+ public void clear() {
+ mSize = 0;
+ }
+
+ /**
+ * Removes all values from this array and release the internal array object if it is too
+ * large.
+ */
+ public void clearWithReleasingLargeArray() {
+ clear();
+ if (mValues.length > MAX_CAPACITY_TO_BE_KEPT) {
+ mValues = EmptyArray.INT;
+ }
+ }
+
+ /**
+ * Returns the value at the specified position in this array.
+ */
+ public int get(@IntRange(from = 0) int index) {
+ return mValues[index];
+ }
+
+ /**
+ * Sets the value at the specified position in this array.
+ */
+ public void set(@IntRange(from = 0) int index, int value) {
+ mValues[index] = value;
+ }
+
+ /**
+ * Returns the number of values in this array.
+ */
+ public @IntRange(from = 0) int size() {
+ return mSize;
+ }
+
+ /**
+ * Returns internal raw array.
+ *
+ * Note that this array may have larger size than you requested.
+ * Use size() instead for getting the actual array size.
+ */
+ public @NonNull int[] getRawArray() {
+ return mValues;
+ }
+ }
+
+ /**
+ * An auto growing float array.
+ */
+ public static class FloatArray {
+
+ private @NonNull float[] mValues;
+ private @IntRange(from = 0) int mSize;
+
+ /**
+ * Creates an empty FloatArray with the default initial capacity.
+ */
+ public FloatArray() {
+ this(10);
+ }
+
+ /**
+ * Creates an empty FloatArray with the specified initial capacity.
+ */
+ public FloatArray(@IntRange(from = 0) int initialCapacity) {
+ if (initialCapacity == 0) {
+ mValues = EmptyArray.FLOAT;
+ } else {
+ mValues = ArrayUtils.newUnpaddedFloatArray(initialCapacity);
+ }
+ mSize = 0;
+ }
+
+ /**
+ * Changes the size of this FloatArray. If this FloatArray is shrinked, the backing array
+ * capacity is unchanged.
+ */
+ public void resize(@IntRange(from = 0) int newSize) {
+ if (newSize > mValues.length) {
+ ensureCapacity(newSize - mSize);
+ }
+ mSize = newSize;
+ }
+
+ /**
+ * Appends the specified value to the end of this array.
+ */
+ public void append(float value) {
+ ensureCapacity(1);
+ mValues[mSize++] = value;
+ }
+
+ /**
+ * Ensures capacity to append at least <code>count</code> values.
+ */
+ private void ensureCapacity(int count) {
+ final int requestedSize = mSize + count;
+ if (requestedSize >= mValues.length) {
+ final int newCapacity = computeNewCapacity(mSize, requestedSize);
+ final float[] newValues = ArrayUtils.newUnpaddedFloatArray(newCapacity);
+ System.arraycopy(mValues, 0, newValues, 0, mSize);
+ mValues = newValues;
+ }
+ }
+
+ /**
+ * Removes all values from this array.
+ */
+ public void clear() {
+ mSize = 0;
+ }
+
+ /**
+ * Removes all values from this array and release the internal array object if it is too
+ * large.
+ */
+ public void clearWithReleasingLargeArray() {
+ clear();
+ if (mValues.length > MAX_CAPACITY_TO_BE_KEPT) {
+ mValues = EmptyArray.FLOAT;
+ }
+ }
+
+ /**
+ * Returns the value at the specified position in this array.
+ */
+ public float get(@IntRange(from = 0) int index) {
+ return mValues[index];
+ }
+
+ /**
+ * Sets the value at the specified position in this array.
+ */
+ public void set(@IntRange(from = 0) int index, float value) {
+ mValues[index] = value;
+ }
+
+ /**
+ * Returns the number of values in this array.
+ */
+ public @IntRange(from = 0) int size() {
+ return mSize;
+ }
+
+ /**
+ * Returns internal raw array.
+ *
+ * Note that this array may have larger size than you requested.
+ * Use size() instead for getting the actual array size.
+ */
+ public @NonNull float[] getRawArray() {
+ return mValues;
+ }
+ }
+}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 4d2a962..2a693a1 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1907,22 +1907,14 @@
private static float measurePara(TextPaint paint, CharSequence text, int start, int end,
TextDirectionHeuristic textDir) {
- MeasuredText mt = MeasuredText.obtain();
+ MeasuredText mt = null;
TextLine tl = TextLine.obtain();
try {
- mt.setPara(text, start, end, textDir);
- Directions directions;
- int dir;
- if (mt.mEasy) {
- directions = DIRS_ALL_LEFT_TO_RIGHT;
- dir = Layout.DIR_LEFT_TO_RIGHT;
- } else {
- directions = AndroidBidi.directions(mt.mDir, mt.mLevels,
- 0, mt.mChars, 0, mt.mLen);
- dir = mt.mDir;
- }
- char[] chars = mt.mChars;
- int len = mt.mLen;
+ mt = MeasuredText.buildForBidi(text, start, end, textDir, mt);
+ final char[] chars = mt.getChars();
+ final int len = chars.length;
+ final Directions directions = mt.getDirections(0, len);
+ final int dir = mt.getParagraphDir();
boolean hasTabs = false;
TabStops tabStops = null;
// leading margins should be taken into account when measuring a paragraph
@@ -1955,7 +1947,9 @@
return margin + Math.abs(tl.metrics(null));
} finally {
TextLine.recycle(tl);
- MeasuredText.recycle(mt);
+ if (mt != null) {
+ mt.recycle();
+ }
}
}
@@ -2272,6 +2266,11 @@
private SpanSet<LineBackgroundSpan> mLineBackgroundSpans;
private int mJustificationMode;
+ /** @hide */
+ @IntDef({DIR_LEFT_TO_RIGHT, DIR_RIGHT_TO_LEFT})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Direction {}
+
public static final int DIR_LEFT_TO_RIGHT = 1;
public static final int DIR_RIGHT_TO_LEFT = -1;
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index 3d9fba7..14d6f9e 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -16,125 +16,436 @@
package android.text;
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.graphics.Paint;
+import android.text.AutoGrowArray.ByteArray;
+import android.text.AutoGrowArray.FloatArray;
+import android.text.AutoGrowArray.IntArray;
+import android.text.Layout.Directions;
import android.text.style.MetricAffectingSpan;
import android.text.style.ReplacementSpan;
-import android.util.Log;
+import android.util.Pools.SynchronizedPool;
-import com.android.internal.util.ArrayUtils;
+import dalvik.annotation.optimization.CriticalNative;
+
+import libcore.util.NativeAllocationRegistry;
+
+import java.util.Arrays;
/**
+ * MeasuredText provides text information for rendering purpose.
+ *
+ * The first motivation of this class is identify the text directions and retrieving individual
+ * character widths. However retrieving character widths is slower than identifying text directions.
+ * Thus, this class provides several builder methods for specific purposes.
+ *
+ * - buildForBidi:
+ * Compute only text directions.
+ * - buildForMeasurement:
+ * Compute text direction and all character widths.
+ * - buildForStaticLayout:
+ * This is bit special. StaticLayout also needs to know text direction and character widths for
+ * line breaking, but all things are done in native code. Similarly, text measurement is done
+ * in native code. So instead of storing result to Java array, this keeps the result in native
+ * code since there is no good reason to move the results to Java layer.
+ *
+ * In addition to the character widths, some additional information is computed for each purposes,
+ * e.g. whole text length for measurement or font metrics for static layout.
+ *
+ * MeasuredText is NOT a thread safe object.
* @hide
*/
-class MeasuredText {
- private static final boolean localLOGV = false;
- CharSequence mText;
- int mTextStart;
- float[] mWidths;
- char[] mChars;
- byte[] mLevels;
- int mDir;
- boolean mEasy;
- int mLen;
+public class MeasuredText {
+ private static final char OBJECT_REPLACEMENT_CHARACTER = '\uFFFC';
- private int mPos;
- private TextPaint mWorkPaint;
+ private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+ MeasuredText.class.getClassLoader(), nGetReleaseFunc(), 1024);
- private MeasuredText() {
- mWorkPaint = new TextPaint();
+ private MeasuredText() {} // Use build static functions instead.
+
+ private static final SynchronizedPool<MeasuredText> sPool = new SynchronizedPool<>(1);
+
+ private static @NonNull MeasuredText obtain() { // Use build static functions instead.
+ final MeasuredText mt = sPool.acquire();
+ return mt != null ? mt : new MeasuredText();
}
- private static final Object[] sLock = new Object[0];
- private static final MeasuredText[] sCached = new MeasuredText[3];
+ /**
+ * Recycle the MeasuredText.
+ *
+ * Do not call any methods after you call this method.
+ */
+ public void recycle() {
+ release();
+ sPool.release(this);
+ }
- static MeasuredText obtain() {
- MeasuredText mt;
- synchronized (sLock) {
- for (int i = sCached.length; --i >= 0;) {
- if (sCached[i] != null) {
- mt = sCached[i];
- sCached[i] = null;
- return mt;
- }
- }
+ // The casted original text.
+ //
+ // This may be null if the passed text is not a Spanned.
+ private @Nullable Spanned mSpanned;
+
+ // The start offset of the target range in the original text (mSpanned);
+ private @IntRange(from = 0) int mTextStart;
+
+ // The length of the target range in the original text.
+ private @IntRange(from = 0) int mTextLength;
+
+ // The copied character buffer for measuring text.
+ //
+ // The length of this array is mTextLength.
+ private @Nullable char[] mCopiedBuffer;
+
+ // The whole paragraph direction.
+ private @Layout.Direction int mParaDir;
+
+ // True if the text is LTR direction and doesn't contain any bidi characters.
+ private boolean mLtrWithoutBidi;
+
+ // The bidi level for individual characters.
+ //
+ // This is empty if mLtrWithoutBidi is true.
+ private @NonNull ByteArray mLevels = new ByteArray();
+
+ // The whole width of the text.
+ // See getWholeWidth comments.
+ private @FloatRange(from = 0.0f) float mWholeWidth;
+
+ // Individual characters' widths.
+ // See getWidths comments.
+ private @Nullable FloatArray mWidths = new FloatArray();
+
+ // The span end positions.
+ // See getSpanEndCache comments.
+ private @Nullable IntArray mSpanEndCache = new IntArray(4);
+
+ // The font metrics.
+ // See getFontMetrics comments.
+ private @Nullable IntArray mFontMetrics = new IntArray(4 * 4);
+
+ // The native MeasuredText.
+ // See getNativePtr comments.
+ // Do not modify these members directly. Use bindNativeObject/unbindNativeObject instead.
+ private /* Maybe Zero */ long mNativePtr = 0;
+ private @Nullable Runnable mNativeObjectCleaner;
+
+ // Associate the native object to this Java object.
+ private void bindNativeObject(/* Non Zero*/ long nativePtr) {
+ mNativePtr = nativePtr;
+ mNativeObjectCleaner = sRegistry.registerNativeAllocation(this, nativePtr);
+ }
+
+ // Decouple the native object from this Java object and release the native object.
+ private void unbindNativeObject() {
+ if (mNativePtr != 0) {
+ mNativeObjectCleaner.run();
+ mNativePtr = 0;
}
- mt = new MeasuredText();
- if (localLOGV) {
- Log.v("MEAS", "new: " + mt);
+ }
+
+ // Following two objects are for avoiding object allocation.
+ private @NonNull TextPaint mCachedPaint = new TextPaint();
+ private @Nullable Paint.FontMetricsInt mCachedFm;
+
+ /**
+ * Releases internal buffers.
+ */
+ public void release() {
+ reset();
+ mLevels.clearWithReleasingLargeArray();
+ mWidths.clearWithReleasingLargeArray();
+ mFontMetrics.clearWithReleasingLargeArray();
+ mSpanEndCache.clearWithReleasingLargeArray();
+ }
+
+ /**
+ * Resets the internal state for starting new text.
+ */
+ private void reset() {
+ mSpanned = null;
+ mCopiedBuffer = null;
+ mWholeWidth = 0;
+ mLevels.clear();
+ mWidths.clear();
+ mFontMetrics.clear();
+ mSpanEndCache.clear();
+ unbindNativeObject();
+ }
+
+ /**
+ * Returns the characters to be measured.
+ *
+ * This is always available.
+ */
+ public @NonNull char[] getChars() {
+ return mCopiedBuffer;
+ }
+
+ /**
+ * Returns the paragraph direction.
+ *
+ * This is always available.
+ */
+ public @Layout.Direction int getParagraphDir() {
+ return mParaDir;
+ }
+
+ /**
+ * Returns the directions.
+ *
+ * This is always available.
+ */
+ public Directions getDirections(@IntRange(from = 0) int start, // inclusive
+ @IntRange(from = 0) int end) { // exclusive
+ if (mLtrWithoutBidi) {
+ return Layout.DIRS_ALL_LEFT_TO_RIGHT;
+ }
+
+ final int length = end - start;
+ return AndroidBidi.directions(mParaDir, mLevels.getRawArray(), start, mCopiedBuffer, start,
+ length);
+ }
+
+ /**
+ * Returns the whole text width.
+ *
+ * This is available only if the MeasureText is computed with computeForMeasurement.
+ * Returns 0 in other cases.
+ */
+ public @FloatRange(from = 0.0f) float getWholeWidth() {
+ return mWholeWidth;
+ }
+
+ /**
+ * Returns the individual character's width.
+ *
+ * This is available only if the MeasureText is computed with computeForMeasurement.
+ * Returns empty array in other cases.
+ */
+ public @NonNull FloatArray getWidths() {
+ return mWidths;
+ }
+
+ /**
+ * Returns the MetricsAffectingSpan end indices.
+ *
+ * If the input text is not a spanned string, this has one value that is the length of the text.
+ *
+ * This is available only if the MeasureText is computed with computeForStaticLayout.
+ * Returns empty array in other cases.
+ */
+ public @NonNull IntArray getSpanEndCache() {
+ return mSpanEndCache;
+ }
+
+ /**
+ * Returns the int array which holds FontMetrics.
+ *
+ * This array holds the repeat of top, bottom, ascent, descent of font metrics value.
+ *
+ * This is available only if the MeasureText is computed with computeForStaticLayout.
+ * Returns empty array in other cases.
+ */
+ public @NonNull IntArray getFontMetrics() {
+ return mFontMetrics;
+ }
+
+ /**
+ * Returns the native ptr of the MeasuredText.
+ *
+ * This is available only if the MeasureText is computed with computeForStaticLayout.
+ * Returns 0 in other cases.
+ */
+ public /* Maybe Zero */ long getNativePtr() {
+ return mNativePtr;
+ }
+
+ /**
+ * Generates new MeasuredText for Bidi computation.
+ *
+ * If recycle is null, this returns new instance. If recycle is not null, this fills computed
+ * result to recycle and returns recycle.
+ *
+ * @param text the character sequence to be measured
+ * @param start the inclusive start offset of the target region in the text
+ * @param end the exclusive end offset of the target region in the text
+ * @param textDir the text direction
+ * @param recycle pass existing MeasuredText if you want to recycle it.
+ *
+ * @return measured text
+ */
+ public static @NonNull MeasuredText buildForBidi(@NonNull CharSequence text,
+ @IntRange(from = 0) int start,
+ @IntRange(from = 0) int end,
+ @NonNull TextDirectionHeuristic textDir,
+ @Nullable MeasuredText recycle) {
+ final MeasuredText mt = recycle == null ? obtain() : recycle;
+ mt.resetAndAnalyzeBidi(text, start, end, textDir);
+ return mt;
+ }
+
+ /**
+ * Generates new MeasuredText for measuring texts.
+ *
+ * If recycle is null, this returns new instance. If recycle is not null, this fills computed
+ * result to recycle and returns recycle.
+ *
+ * @param paint the paint to be used for rendering the text.
+ * @param text the character sequence to be measured
+ * @param start the inclusive start offset of the target region in the text
+ * @param end the exclusive end offset of the target region in the text
+ * @param textDir the text direction
+ * @param recycle pass existing MeasuredText if you want to recycle it.
+ *
+ * @return measured text
+ */
+ public static @NonNull MeasuredText buildForMeasurement(@NonNull TextPaint paint,
+ @NonNull CharSequence text,
+ @IntRange(from = 0) int start,
+ @IntRange(from = 0) int end,
+ @NonNull TextDirectionHeuristic textDir,
+ @Nullable MeasuredText recycle) {
+ final MeasuredText mt = recycle == null ? obtain() : recycle;
+ mt.resetAndAnalyzeBidi(text, start, end, textDir);
+
+ mt.mWidths.resize(mt.mTextLength);
+ if (mt.mTextLength == 0) {
+ return mt;
+ }
+
+ if (mt.mSpanned == null) {
+ // No style change by MetricsAffectingSpan. Just measure all text.
+ mt.applyMetricsAffectingSpan(
+ paint, null /* spans */, start, end, 0 /* native static layout ptr */);
+ } else {
+ // There may be a MetricsAffectingSpan. Split into span transitions and apply styles.
+ int spanEnd;
+ for (int spanStart = start; spanStart < end; spanStart = spanEnd) {
+ spanEnd = mt.mSpanned.nextSpanTransition(spanStart, end, MetricAffectingSpan.class);
+ MetricAffectingSpan[] spans = mt.mSpanned.getSpans(spanStart, spanEnd,
+ MetricAffectingSpan.class);
+ spans = TextUtils.removeEmptySpans(spans, mt.mSpanned, MetricAffectingSpan.class);
+ mt.applyMetricsAffectingSpan(
+ paint, spans, spanStart, spanEnd, 0 /* native static layout ptr */);
+ }
}
return mt;
}
- static MeasuredText recycle(MeasuredText mt) {
- mt.finish();
- synchronized(sLock) {
- for (int i = 0; i < sCached.length; ++i) {
- if (sCached[i] == null) {
- sCached[i] = mt;
- mt.mText = null;
- break;
+ /**
+ * Generates new MeasuredText for StaticLayout.
+ *
+ * If recycle is null, this returns new instance. If recycle is not null, this fills computed
+ * result to recycle and returns recycle.
+ *
+ * @param paint the paint to be used for rendering the text.
+ * @param text the character sequence to be measured
+ * @param start the inclusive start offset of the target region in the text
+ * @param end the exclusive end offset of the target region in the text
+ * @param textDir the text direction
+ * @param recycle pass existing MeasuredText if you want to recycle it.
+ *
+ * @return measured text
+ */
+ public static @NonNull MeasuredText buildForStaticLayout(
+ @NonNull TextPaint paint,
+ @NonNull CharSequence text,
+ @IntRange(from = 0) int start,
+ @IntRange(from = 0) int end,
+ @NonNull TextDirectionHeuristic textDir,
+ @Nullable MeasuredText recycle) {
+ final MeasuredText mt = recycle == null ? obtain() : recycle;
+ mt.resetAndAnalyzeBidi(text, start, end, textDir);
+ if (mt.mTextLength == 0) {
+ // Need to build empty native measured text for StaticLayout.
+ // TODO: Stop creating empty measured text for empty lines.
+ long nativeBuilderPtr = nInitBuilder();
+ try {
+ mt.bindNativeObject(nBuildNativeMeasuredText(nativeBuilderPtr, mt.mCopiedBuffer));
+ } finally {
+ nFreeBuilder(nativeBuilderPtr);
+ }
+ return mt;
+ }
+
+ long nativeBuilderPtr = nInitBuilder();
+ try {
+ if (mt.mSpanned == null) {
+ // No style change by MetricsAffectingSpan. Just measure all text.
+ mt.applyMetricsAffectingSpan(paint, null /* spans */, start, end, nativeBuilderPtr);
+ mt.mSpanEndCache.append(end);
+ } else {
+ // There may be a MetricsAffectingSpan. Split into span transitions and apply
+ // styles.
+ int spanEnd;
+ for (int spanStart = start; spanStart < end; spanStart = spanEnd) {
+ spanEnd = mt.mSpanned.nextSpanTransition(spanStart, end,
+ MetricAffectingSpan.class);
+ MetricAffectingSpan[] spans = mt.mSpanned.getSpans(spanStart, spanEnd,
+ MetricAffectingSpan.class);
+ spans = TextUtils.removeEmptySpans(spans, mt.mSpanned,
+ MetricAffectingSpan.class);
+ mt.applyMetricsAffectingSpan(paint, spans, spanStart, spanEnd,
+ nativeBuilderPtr);
+ mt.mSpanEndCache.append(spanEnd);
}
}
+ mt.bindNativeObject(nBuildNativeMeasuredText(nativeBuilderPtr, mt.mCopiedBuffer));
+ } finally {
+ nFreeBuilder(nativeBuilderPtr);
}
- return null;
- }
- void finish() {
- mText = null;
- if (mLen > 1000) {
- mWidths = null;
- mChars = null;
- mLevels = null;
- }
+ return mt;
}
/**
- * Analyzes text for bidirectional runs. Allocates working buffers.
+ * Reset internal state and analyzes text for bidirectional runs.
+ *
+ * @param text the character sequence to be measured
+ * @param start the inclusive start offset of the target region in the text
+ * @param end the exclusive end offset of the target region in the text
+ * @param textDir the text direction
*/
- void setPara(CharSequence text, int start, int end, TextDirectionHeuristic textDir) {
- mText = text;
+ private void resetAndAnalyzeBidi(@NonNull CharSequence text,
+ @IntRange(from = 0) int start, // inclusive
+ @IntRange(from = 0) int end, // exclusive
+ @NonNull TextDirectionHeuristic textDir) {
+ reset();
+ mSpanned = text instanceof Spanned ? (Spanned) text : null;
mTextStart = start;
+ mTextLength = end - start;
- int len = end - start;
- mLen = len;
- mPos = 0;
-
- if (mWidths == null || mWidths.length < len) {
- mWidths = ArrayUtils.newUnpaddedFloatArray(len);
+ if (mCopiedBuffer == null || mCopiedBuffer.length != mTextLength) {
+ mCopiedBuffer = new char[mTextLength];
}
- if (mChars == null || mChars.length != len) {
- mChars = new char[len];
- }
- TextUtils.getChars(text, start, end, mChars, 0);
+ TextUtils.getChars(text, start, end, mCopiedBuffer, 0);
- if (text instanceof Spanned) {
- Spanned spanned = (Spanned) text;
- ReplacementSpan[] spans = spanned.getSpans(start, end,
- ReplacementSpan.class);
+ // Replace characters associated with ReplacementSpan to U+FFFC.
+ if (mSpanned != null) {
+ ReplacementSpan[] spans = mSpanned.getSpans(start, end, ReplacementSpan.class);
for (int i = 0; i < spans.length; i++) {
- int startInPara = spanned.getSpanStart(spans[i]) - start;
- int endInPara = spanned.getSpanEnd(spans[i]) - start;
- // The span interval may be larger and must be restricted to [start, end[
+ int startInPara = mSpanned.getSpanStart(spans[i]) - start;
+ int endInPara = mSpanned.getSpanEnd(spans[i]) - start;
+ // The span interval may be larger and must be restricted to [start, end)
if (startInPara < 0) startInPara = 0;
- if (endInPara > len) endInPara = len;
- for (int j = startInPara; j < endInPara; j++) {
- mChars[j] = '\uFFFC'; // object replacement character
- }
+ if (endInPara > mTextLength) endInPara = mTextLength;
+ Arrays.fill(mCopiedBuffer, startInPara, endInPara, OBJECT_REPLACEMENT_CHARACTER);
}
}
if ((textDir == TextDirectionHeuristics.LTR ||
textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR ||
textDir == TextDirectionHeuristics.ANYRTL_LTR) &&
- TextUtils.doesNotNeedBidi(mChars, 0, len)) {
- mDir = Layout.DIR_LEFT_TO_RIGHT;
- mEasy = true;
+ TextUtils.doesNotNeedBidi(mCopiedBuffer, 0, mTextLength)) {
+ mLevels.clear();
+ mParaDir = Layout.DIR_LEFT_TO_RIGHT;
+ mLtrWithoutBidi = true;
} else {
- if (mLevels == null || mLevels.length < len) {
- mLevels = ArrayUtils.newUnpaddedByteArray(len);
- }
- int bidiRequest;
+ final int bidiRequest;
if (textDir == TextDirectionHeuristics.LTR) {
bidiRequest = Layout.DIR_REQUEST_LTR;
} else if (textDir == TextDirectionHeuristics.RTL) {
@@ -144,122 +455,147 @@
} else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_RTL) {
bidiRequest = Layout.DIR_REQUEST_DEFAULT_RTL;
} else {
- boolean isRtl = textDir.isRtl(mChars, 0, len);
+ final boolean isRtl = textDir.isRtl(mCopiedBuffer, 0, mTextLength);
bidiRequest = isRtl ? Layout.DIR_REQUEST_RTL : Layout.DIR_REQUEST_LTR;
}
- mDir = AndroidBidi.bidi(bidiRequest, mChars, mLevels);
- mEasy = false;
+ mLevels.resize(mTextLength);
+ mParaDir = AndroidBidi.bidi(bidiRequest, mCopiedBuffer, mLevels.getRawArray());
+ mLtrWithoutBidi = false;
+ }
+ }
+
+ private void applyReplacementRun(@NonNull ReplacementSpan replacement,
+ @IntRange(from = 0) int start, // inclusive, in copied buffer
+ @IntRange(from = 0) int end, // exclusive, in copied buffer
+ /* Maybe Zero */ long nativeBuilderPtr) {
+ // Use original text. Shouldn't matter.
+ // TODO: passing uninitizlied FontMetrics to developers. Do we need to keep this for
+ // backward compatibility? or Should we initialize them for getFontMetricsInt?
+ final float width = replacement.getSize(
+ mCachedPaint, mSpanned, start + mTextStart, end + mTextStart, mCachedFm);
+ if (nativeBuilderPtr == 0) {
+ // Assigns all width to the first character. This is the same behavior as minikin.
+ mWidths.set(start, width);
+ if (end > start + 1) {
+ Arrays.fill(mWidths.getRawArray(), start + 1, end, 0.0f);
+ }
+ mWholeWidth += width;
+ } else {
+ nAddReplacementRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), start, end,
+ width);
+ }
+ }
+
+ private void applyStyleRun(@IntRange(from = 0) int start, // inclusive, in copied buffer
+ @IntRange(from = 0) int end, // exclusive, in copied buffer
+ /* Maybe Zero */ long nativeBuilderPtr) {
+ if (nativeBuilderPtr != 0) {
+ mCachedPaint.getFontMetricsInt(mCachedFm);
+ }
+
+ if (mLtrWithoutBidi) {
+ // If the whole text is LTR direction, just apply whole region.
+ if (nativeBuilderPtr == 0) {
+ mWholeWidth += mCachedPaint.getTextRunAdvances(
+ mCopiedBuffer, start, end - start, start, end - start, false /* isRtl */,
+ mWidths.getRawArray(), start);
+ } else {
+ nAddStyleRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), start, end,
+ false /* isRtl */);
+ }
+ } else {
+ // If there is multiple bidi levels, split into individual bidi level and apply style.
+ byte level = mLevels.get(start);
+ // Note that the empty text or empty range won't reach this method.
+ // Safe to search from start + 1.
+ for (int levelStart = start, levelEnd = start + 1;; ++levelEnd) {
+ if (levelEnd == end || mLevels.get(levelEnd) != level) { // transition point
+ final boolean isRtl = (level & 0x1) != 0;
+ if (nativeBuilderPtr == 0) {
+ final int levelLength = levelEnd - levelStart;
+ mWholeWidth += mCachedPaint.getTextRunAdvances(
+ mCopiedBuffer, levelStart, levelLength, levelStart, levelLength,
+ isRtl, mWidths.getRawArray(), levelStart);
+ } else {
+ nAddStyleRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), levelStart,
+ levelEnd, isRtl);
+ }
+ if (levelEnd == end) {
+ break;
+ }
+ levelStart = levelEnd;
+ level = mLevels.get(levelEnd);
+ }
+ }
+ }
+ }
+
+ private void applyMetricsAffectingSpan(
+ @NonNull TextPaint paint,
+ @Nullable MetricAffectingSpan[] spans,
+ @IntRange(from = 0) int start, // inclusive, in original text buffer
+ @IntRange(from = 0) int end, // exclusive, in original text buffer
+ /* Maybe Zero */ long nativeBuilderPtr) {
+ mCachedPaint.set(paint);
+ // XXX paint should not have a baseline shift, but...
+ mCachedPaint.baselineShift = 0;
+
+ final boolean needFontMetrics = nativeBuilderPtr != 0;
+
+ if (needFontMetrics && mCachedFm == null) {
+ mCachedFm = new Paint.FontMetricsInt();
+ }
+
+ ReplacementSpan replacement = null;
+ if (spans != null) {
+ for (int i = 0; i < spans.length; i++) {
+ MetricAffectingSpan span = spans[i];
+ if (span instanceof ReplacementSpan) {
+ // The last ReplacementSpan is effective for backward compatibility reasons.
+ replacement = (ReplacementSpan) span;
+ } else {
+ // TODO: No need to call updateMeasureState for ReplacementSpan as well?
+ span.updateMeasureState(mCachedPaint);
+ }
+ }
+ }
+
+ final int startInCopiedBuffer = start - mTextStart;
+ final int endInCopiedBuffer = end - mTextStart;
+
+ if (replacement != null) {
+ applyReplacementRun(replacement, startInCopiedBuffer, endInCopiedBuffer,
+ nativeBuilderPtr);
+ } else {
+ applyStyleRun(startInCopiedBuffer, endInCopiedBuffer, nativeBuilderPtr);
+ }
+
+ if (needFontMetrics) {
+ if (mCachedPaint.baselineShift < 0) {
+ mCachedFm.ascent += mCachedPaint.baselineShift;
+ mCachedFm.top += mCachedPaint.baselineShift;
+ } else {
+ mCachedFm.descent += mCachedPaint.baselineShift;
+ mCachedFm.bottom += mCachedPaint.baselineShift;
+ }
+
+ mFontMetrics.append(mCachedFm.top);
+ mFontMetrics.append(mCachedFm.bottom);
+ mFontMetrics.append(mCachedFm.ascent);
+ mFontMetrics.append(mCachedFm.descent);
}
}
/**
- * Apply the style.
+ * Returns the maximum index that the accumulated width not exceeds the width.
*
- * If nativeStaticLayoutPtr is 0, this method measures the styled text width.
- * If nativeStaticLayoutPtr is not 0, this method just passes the style information to native
- * code by calling StaticLayout.addstyleRun() and returns 0.
+ * If forward=false is passed, returns the minimum index from the end instead.
+ *
+ * This only works if the MeasuredText is computed with computeForMeasurement.
+ * Undefined behavior in other case.
*/
- float addStyleRun(TextPaint paint, int len, Paint.FontMetricsInt fm,
- long nativeStaticLayoutPtr) {
- if (fm != null) {
- paint.getFontMetricsInt(fm);
- }
-
- final int p = mPos;
- mPos = p + len;
-
- if (mEasy) {
- final boolean isRtl = mDir != Layout.DIR_LEFT_TO_RIGHT;
- if (nativeStaticLayoutPtr == 0) {
- return paint.getTextRunAdvances(mChars, p, len, p, len, isRtl, mWidths, p);
- } else {
- StaticLayout.addStyleRun(nativeStaticLayoutPtr, paint, p, p + len, isRtl);
- return 0.0f; // Builder.addStyleRun doesn't return the width.
- }
- }
-
- float totalAdvance = 0;
- int level = mLevels[p];
- for (int q = p, i = p + 1, e = p + len;; ++i) {
- if (i == e || mLevels[i] != level) {
- final boolean isRtl = (level & 0x1) != 0;
- if (nativeStaticLayoutPtr == 0) {
- totalAdvance +=
- paint.getTextRunAdvances(mChars, q, i - q, q, i - q, isRtl, mWidths, q);
- } else {
- // Builder.addStyleRun doesn't return the width.
- StaticLayout.addStyleRun(nativeStaticLayoutPtr, paint, q, i, isRtl);
- }
- if (i == e) {
- break;
- }
- q = i;
- level = mLevels[i];
- }
- }
- return totalAdvance; // If nativeStaticLayoutPtr is 0, the result is zero.
- }
-
- float addStyleRun(TextPaint paint, int len, Paint.FontMetricsInt fm) {
- return addStyleRun(paint, len, fm, 0 /* native ptr */);
- }
-
- float addStyleRun(TextPaint paint, MetricAffectingSpan[] spans, int len,
- Paint.FontMetricsInt fm, long nativeStaticLayoutPtr) {
-
- TextPaint workPaint = mWorkPaint;
- workPaint.set(paint);
- // XXX paint should not have a baseline shift, but...
- workPaint.baselineShift = 0;
-
- ReplacementSpan replacement = null;
- for (int i = 0; i < spans.length; i++) {
- MetricAffectingSpan span = spans[i];
- if (span instanceof ReplacementSpan) {
- replacement = (ReplacementSpan)span;
- } else {
- span.updateMeasureState(workPaint);
- }
- }
-
- float wid;
- if (replacement == null) {
- wid = addStyleRun(workPaint, len, fm, nativeStaticLayoutPtr);
- } else {
- // Use original text. Shouldn't matter.
- wid = replacement.getSize(workPaint, mText, mTextStart + mPos,
- mTextStart + mPos + len, fm);
- if (nativeStaticLayoutPtr == 0) {
- float[] w = mWidths;
- w[mPos] = wid;
- for (int i = mPos + 1, e = mPos + len; i < e; i++)
- w[i] = 0;
- } else {
- StaticLayout.addReplacementRun(nativeStaticLayoutPtr, paint, mPos, mPos + len, wid);
- }
- mPos += len;
- }
-
- if (fm != null) {
- if (workPaint.baselineShift < 0) {
- fm.ascent += workPaint.baselineShift;
- fm.top += workPaint.baselineShift;
- } else {
- fm.descent += workPaint.baselineShift;
- fm.bottom += workPaint.baselineShift;
- }
- }
-
- return wid;
- }
-
- float addStyleRun(TextPaint paint, MetricAffectingSpan[] spans, int len,
- Paint.FontMetricsInt fm) {
- return addStyleRun(paint, spans, len, fm, 0 /* native ptr */);
- }
-
- int breakText(int limit, boolean forwards, float width) {
- float[] w = mWidths;
+ @IntRange(from = 0) int breakText(int limit, boolean forwards, float width) {
+ float[] w = mWidths.getRawArray();
if (forwards) {
int i = 0;
while (i < limit) {
@@ -267,7 +603,7 @@
if (width < 0.0f) break;
i++;
}
- while (i > 0 && mChars[i - 1] == ' ') i--;
+ while (i > 0 && mCopiedBuffer[i - 1] == ' ') i--;
return i;
} else {
int i = limit - 1;
@@ -276,19 +612,65 @@
if (width < 0.0f) break;
i--;
}
- while (i < limit - 1 && (mChars[i + 1] == ' ' || w[i + 1] == 0.0f)) {
+ while (i < limit - 1 && (mCopiedBuffer[i + 1] == ' ' || w[i + 1] == 0.0f)) {
i++;
}
return limit - i - 1;
}
}
- float measure(int start, int limit) {
+ /**
+ * Returns the length of the substring.
+ *
+ * This only works if the MeasuredText is computed with computeForMeasurement.
+ * Undefined behavior in other case.
+ */
+ @FloatRange(from = 0.0f) float measure(int start, int limit) {
float width = 0;
- float[] w = mWidths;
+ float[] w = mWidths.getRawArray();
for (int i = start; i < limit; ++i) {
width += w[i];
}
return width;
}
+
+ private static native /* Non Zero */ long nInitBuilder();
+
+ /**
+ * Apply style to make native measured text.
+ *
+ * @param nativeBuilderPtr The native MeasuredText builder pointer.
+ * @param paintPtr The native paint pointer to be applied.
+ * @param start The start offset in the copied buffer.
+ * @param end The end offset in the copied buffer.
+ * @param isRtl True if the text is RTL.
+ */
+ private static native void nAddStyleRun(/* Non Zero */ long nativeBuilderPtr,
+ /* Non Zero */ long paintPtr,
+ @IntRange(from = 0) int start,
+ @IntRange(from = 0) int end,
+ boolean isRtl);
+
+ /**
+ * Apply ReplacementRun to make native measured text.
+ *
+ * @param nativeBuilderPtr The native MeasuredText builder pointer.
+ * @param paintPtr The native paint pointer to be applied.
+ * @param start The start offset in the copied buffer.
+ * @param end The end offset in the copied buffer.
+ * @param width The width of the replacement.
+ */
+ private static native void nAddReplacementRun(/* Non Zero */ long nativeBuilderPtr,
+ /* Non Zero */ long paintPtr,
+ @IntRange(from = 0) int start,
+ @IntRange(from = 0) int end,
+ @FloatRange(from = 0) float width);
+
+ private static native long nBuildNativeMeasuredText(/* Non Zero */ long nativeBuilderPtr,
+ @NonNull char[] text);
+
+ private static native void nFreeBuilder(/* Non Zero */ long nativeBuilderPtr);
+
+ @CriticalNative
+ private static native /* Non Zero */ long nGetReleaseFunc();
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index c0fc44f..400b075 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -21,10 +21,10 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Paint;
+import android.text.AutoGrowArray.FloatArray;
import android.text.style.LeadingMarginSpan;
import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
import android.text.style.LineHeightSpan;
-import android.text.style.MetricAffectingSpan;
import android.text.style.TabStopSpan;
import android.util.Log;
import android.util.Pools.SynchronizedPool;
@@ -48,6 +48,18 @@
* Canvas.drawText()} directly.</p>
*/
public class StaticLayout extends Layout {
+ /*
+ * The break iteration is done in native code. The protocol for using the native code is as
+ * follows.
+ *
+ * First, call nInit to setup native line breaker object. Then, for each paragraph, do the
+ * following:
+ *
+ * - Create MeasuredText by MeasuredText.buildForStaticLayout which measures in native.
+ * - Run nComputeLineBreaks() to obtain line breaks for the paragraph.
+ *
+ * After all paragraphs, call finish() to release expensive buffers.
+ */
static final String TAG = "StaticLayout";
@@ -99,8 +111,6 @@
b.mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
b.mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
b.mJustificationMode = Layout.JUSTIFICATION_MODE_NONE;
-
- b.mMeasuredText = MeasuredText.obtain();
return b;
}
@@ -111,8 +121,6 @@
private static void recycle(@NonNull Builder b) {
b.mPaint = null;
b.mText = null;
- MeasuredText.recycle(b.mMeasuredText);
- b.mMeasuredText = null;
b.mLeftIndents = null;
b.mRightIndents = null;
b.mLeftPaddings = null;
@@ -128,7 +136,6 @@
mRightIndents = null;
mLeftPaddings = null;
mRightPaddings = null;
- mMeasuredText.finish();
}
public Builder setText(CharSequence source) {
@@ -444,9 +451,6 @@
private final Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
- // This will go away and be subsumed by native builder code
- private MeasuredText mMeasuredText;
-
private static final SynchronizedPool<Builder> sPool = new SynchronizedPool<>(3);
}
@@ -618,11 +622,7 @@
TextUtils.TruncateAt ellipsize = b.mEllipsize;
final boolean addLastLineSpacing = b.mAddLastLineLineSpacing;
LineBreaks lineBreaks = new LineBreaks(); // TODO: move to builder to avoid allocation costs
- // store span end locations
- int[] spanEndCache = new int[4];
- // store fontMetrics per span range
- // must be a multiple of 4 (and > 0) (store top, bottom, ascent, and descent per range)
- int[] fmCache = new int[4 * 4];
+ FloatArray widths = new FloatArray();
mLineCount = 0;
mEllipsized = false;
@@ -634,8 +634,6 @@
Paint.FontMetricsInt fm = b.mFontMetricsInt;
int[] chooseHtv = null;
- MeasuredText measured = b.mMeasuredText;
-
Spanned spanned = null;
if (source instanceof Spanned)
spanned = (Spanned) source;
@@ -662,6 +660,7 @@
b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE,
indents, mLeftPaddings, mRightPaddings);
+ MeasuredText measured = null;
try {
int paraEnd;
for (int paraStart = bufStart; paraStart <= bufEnd; paraStart = paraEnd) {
@@ -721,13 +720,6 @@
}
}
- measured.setPara(source, paraStart, paraEnd, textDir);
- char[] chs = measured.mChars;
- float[] widths = measured.mWidths;
- byte[] chdirs = measured.mLevels;
- int dir = measured.mDir;
- boolean easy = measured.mEasy;
-
// tab stop locations
int[] variableTabStops = null;
if (spanned != null) {
@@ -743,56 +735,24 @@
}
}
+ measured = MeasuredText.buildForStaticLayout(
+ paint, source, paraStart, paraEnd, textDir, measured);
+ final char[] chs = measured.getChars();
+ final int[] spanEndCache = measured.getSpanEndCache().getRawArray();
+ final int[] fmCache = measured.getFontMetrics().getRawArray();
+ // TODO: Stop keeping duplicated width copy in native and Java.
+ widths.resize(chs.length);
+
// measurement has to be done before performing line breaking
// but we don't want to recompute fontmetrics or span ranges the
// second time, so we cache those and then use those stored values
- int fmCacheCount = 0;
- int spanEndCacheCount = 0;
- for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
- if (fmCacheCount * 4 >= fmCache.length) {
- int[] grow = new int[fmCacheCount * 4 * 2];
- System.arraycopy(fmCache, 0, grow, 0, fmCacheCount * 4);
- fmCache = grow;
- }
-
- if (spanEndCacheCount >= spanEndCache.length) {
- int[] grow = new int[spanEndCacheCount * 2];
- System.arraycopy(spanEndCache, 0, grow, 0, spanEndCacheCount);
- spanEndCache = grow;
- }
-
- if (spanned == null) {
- spanEnd = paraEnd;
- int spanLen = spanEnd - spanStart;
- measured.addStyleRun(paint, spanLen, fm, nativePtr);
- } else {
- spanEnd = spanned.nextSpanTransition(spanStart, paraEnd,
- MetricAffectingSpan.class);
- int spanLen = spanEnd - spanStart;
- MetricAffectingSpan[] spans =
- spanned.getSpans(spanStart, spanEnd, MetricAffectingSpan.class);
- spans = TextUtils.removeEmptySpans(spans, spanned,
- MetricAffectingSpan.class);
- measured.addStyleRun(paint, spans, spanLen, fm, nativePtr);
- }
-
- // the order of storage here (top, bottom, ascent, descent) has to match the
- // code below where these values are retrieved
- fmCache[fmCacheCount * 4 + 0] = fm.top;
- fmCache[fmCacheCount * 4 + 1] = fm.bottom;
- fmCache[fmCacheCount * 4 + 2] = fm.ascent;
- fmCache[fmCacheCount * 4 + 3] = fm.descent;
- fmCacheCount++;
-
- spanEndCache[spanEndCacheCount] = spanEnd;
- spanEndCacheCount++;
- }
int breakCount = nComputeLineBreaks(
nativePtr,
// Inputs
chs,
+ measured.getNativePtr(),
paraEnd - paraStart,
firstWidth,
firstWidthLineCount,
@@ -809,7 +769,7 @@
lineBreaks.ascents,
lineBreaks.descents,
lineBreaks.flags,
- widths);
+ widths.getRawArray());
final int[] breaks = lineBreaks.breaks;
final float[] lineWidths = lineBreaks.widths;
@@ -832,7 +792,7 @@
width += lineWidths[i];
} else {
for (int j = (i == 0 ? 0 : breaks[i - 1]); j < breaks[i]; j++) {
- width += widths[j];
+ width += widths.get(j);
}
}
flag |= flags[i] & TAB_MASK;
@@ -896,10 +856,10 @@
v = out(source, here, endPos,
ascent, descent, fmTop, fmBottom,
v, spacingmult, spacingadd, chooseHt, chooseHtv, fm,
- flags[breakIndex], needMultiply, chdirs, dir, easy, bufEnd,
- includepad, trackpad, addLastLineSpacing, chs, widths, paraStart,
- ellipsize, ellipsizedWidth, lineWidths[breakIndex], paint,
- moreChars);
+ flags[breakIndex], needMultiply, measured, bufEnd,
+ includepad, trackpad, addLastLineSpacing, chs, widths.getRawArray(),
+ paraStart, ellipsize, ellipsizedWidth, lineWidths[breakIndex],
+ paint, moreChars);
if (endPos < spanEnd) {
// preserve metrics for current span
@@ -927,22 +887,22 @@
if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE)
&& mLineCount < mMaximumVisibleLineCount) {
- measured.setPara(source, bufEnd, bufEnd, textDir);
-
paint.getFontMetricsInt(fm);
-
v = out(source,
bufEnd, bufEnd, fm.ascent, fm.descent,
fm.top, fm.bottom,
v,
spacingmult, spacingadd, null,
null, fm, 0,
- needMultiply, measured.mLevels, measured.mDir, measured.mEasy, bufEnd,
+ needMultiply, null, bufEnd,
includepad, trackpad, addLastLineSpacing, null,
null, bufStart, ellipsize,
ellipsizedWidth, 0, paint, false);
}
} finally {
+ if (measured != null) {
+ measured.recycle();
+ }
nFinish(nativePtr);
}
}
@@ -952,8 +912,8 @@
private int out(final CharSequence text, final int start, final int end, int above, int below,
int top, int bottom, int v, final float spacingmult, final float spacingadd,
final LineHeightSpan[] chooseHt, final int[] chooseHtv, final Paint.FontMetricsInt fm,
- final int flags, final boolean needMultiply, final byte[] chdirs, final int dir,
- final boolean easy, final int bufEnd, final boolean includePad, final boolean trackPad,
+ final int flags, final boolean needMultiply, @Nullable final MeasuredText measured,
+ final int bufEnd, final boolean includePad, final boolean trackPad,
final boolean addLastLineLineSpacing, final char[] chs, final float[] widths,
final int widthStart, final TextUtils.TruncateAt ellipsize, final float ellipsisWidth,
final float textWidth, final TextPaint paint, final boolean moreChars) {
@@ -961,6 +921,7 @@
final int off = j * mColumns;
final int want = off + mColumns + TOP;
int[] lines = mLines;
+ final int dir = (start == end) ? Layout.DIR_LEFT_TO_RIGHT : measured.getParagraphDir();
if (want >= lines.length) {
final int[] grow = ArrayUtils.newUnpaddedIntArray(GrowingArrayUtils.growSize(want));
@@ -986,16 +947,11 @@
// one bit for start field
lines[off + TAB] |= flags & TAB_MASK;
lines[off + HYPHEN] = flags;
-
lines[off + DIR] |= dir << DIR_SHIFT;
- // easy means all chars < the first RTL, so no emoji, no nothing
- // XXX a run with no text or all spaces is easy but might be an empty
- // RTL paragraph. Make sure easy is false if this is the case.
- if (easy) {
- mLineDirections[j] = DIRS_ALL_LEFT_TO_RIGHT;
+ if (start == end) {
+ mLineDirections[j] = Layout.DIRS_ALL_LEFT_TO_RIGHT;
} else {
- mLineDirections[j] = AndroidBidi.directions(dir, chdirs, start - widthStart, chs,
- start - widthStart, end - start);
+ mLineDirections[j] = measured.getDirections(start - widthStart, end - widthStart);
}
final boolean firstLine = (j == 0);
@@ -1473,33 +1429,6 @@
mMaxLineHeight : super.getHeight();
}
- /**
- * Measurement and break iteration is done in native code. The protocol for using
- * the native code is as follows.
- *
- * First, call nInit to setup native line breaker object. Then, for each paragraph, do the
- * following:
- *
- * - Call one of the following methods for each run within the paragraph depending on the type
- * of run:
- * + addStyleRun (a text run, to be measured in native code)
- * + addReplacementRun (a replacement run, width is given)
- *
- * - Run nComputeLineBreaks() to obtain line breaks for the paragraph.
- *
- * After all paragraphs, call finish() to release expensive buffers.
- */
-
- /* package */ static void addStyleRun(long nativePtr, TextPaint paint, int start, int end,
- boolean isRtl) {
- nAddStyleRun(nativePtr, paint.getNativeInstance(), start, end, isRtl);
- }
-
- /* package */ static void addReplacementRun(long nativePtr, TextPaint paint, int start, int end,
- float width) {
- nAddReplacementRun(nativePtr, paint.getNativeInstance(), start, end, width);
- }
-
@FastNative
private static native long nInit(
@BreakStrategy int breakStrategy,
@@ -1512,17 +1441,6 @@
@CriticalNative
private static native void nFinish(long nativePtr);
- @CriticalNative
- private static native void nAddStyleRun(
- /* non-zero */ long nativePtr, /* non-zero */ long nativePaint,
- @IntRange(from = 0) int start, @IntRange(from = 0) int end, boolean isRtl);
-
- @CriticalNative
- private static native void nAddReplacementRun(
- /* non-zero */ long nativePtr, /* non-zero */ long nativePaint,
- @IntRange(from = 0) int start, @IntRange(from = 0) int end,
- @FloatRange(from = 0.0f) float width);
-
// populates LineBreaks and returns the number of breaks found
//
// the arrays inside the LineBreaks objects are passed in as well
@@ -1535,6 +1453,7 @@
// Inputs
@NonNull char[] text,
+ /* Non Zero */ long measuredTextPtr,
@IntRange(from = 0) int length,
@FloatRange(from = 0.0f) float firstWidth,
@IntRange(from = 0) int firstWidthLineCount,
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index cbdaa69..9c9fbf2 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -42,7 +42,6 @@
import android.text.style.ForegroundColorSpan;
import android.text.style.LeadingMarginSpan;
import android.text.style.LocaleSpan;
-import android.text.style.MetricAffectingSpan;
import android.text.style.ParagraphStyle;
import android.text.style.QuoteSpan;
import android.text.style.RelativeSizeSpan;
@@ -1251,10 +1250,11 @@
@NonNull String ellipsis) {
final int len = text.length();
- final MeasuredText mt = MeasuredText.obtain();
+ MeasuredText mt = null;
MeasuredText resultMt = null;
try {
- float width = setPara(mt, paint, text, 0, text.length(), textDir);
+ mt = MeasuredText.buildForMeasurement(paint, text, 0, text.length(), textDir, mt);
+ float width = mt.getWholeWidth();
if (width <= avail) {
if (callback != null) {
@@ -1263,7 +1263,6 @@
return text;
}
- resultMt = MeasuredText.obtain();
// First estimate of effective width of ellipsis.
float ellipsisWidth = paint.measureText(ellipsis);
int numberOfTries = 0;
@@ -1290,7 +1289,7 @@
}
}
- final char[] buf = mt.mChars;
+ final char[] buf = mt.getChars();
final Spanned sp = text instanceof Spanned ? (Spanned) text : null;
final int removed = end - start;
@@ -1333,7 +1332,9 @@
if (remaining == 0) { // All text is gone.
textFits = true;
} else {
- width = setPara(resultMt, paint, result, 0, result.length(), textDir);
+ resultMt = MeasuredText.buildForMeasurement(
+ paint, result, 0, result.length(), textDir, resultMt);
+ width = resultMt.getWholeWidth();
if (width <= avail) {
textFits = true;
} else {
@@ -1357,9 +1358,11 @@
}
return result;
} finally {
- MeasuredText.recycle(mt);
+ if (mt != null) {
+ mt.recycle();
+ }
if (resultMt != null) {
- MeasuredText.recycle(resultMt);
+ resultMt.recycle();
}
}
}
@@ -1476,15 +1479,17 @@
public static CharSequence commaEllipsize(CharSequence text, TextPaint p,
float avail, String oneMore, String more, TextDirectionHeuristic textDir) {
- MeasuredText mt = MeasuredText.obtain();
+ MeasuredText mt = null;
+ MeasuredText tempMt = null;
try {
int len = text.length();
- float width = setPara(mt, p, text, 0, len, textDir);
+ mt = MeasuredText.buildForMeasurement(p, text, 0, len, textDir, mt);
+ final float width = mt.getWholeWidth();
if (width <= avail) {
return text;
}
- char[] buf = mt.mChars;
+ char[] buf = mt.getChars();
int commaCount = 0;
for (int i = 0; i < len; i++) {
@@ -1500,9 +1505,8 @@
int w = 0;
int count = 0;
- float[] widths = mt.mWidths;
+ float[] widths = mt.getWidths().getRawArray();
- MeasuredText tempMt = MeasuredText.obtain();
for (int i = 0; i < len; i++) {
w += widths[i];
@@ -1519,8 +1523,9 @@
}
// XXX this is probably ok, but need to look at it more
- tempMt.setPara(format, 0, format.length(), textDir);
- float moreWid = tempMt.addStyleRun(p, tempMt.mLen, null);
+ tempMt = MeasuredText.buildForMeasurement(
+ p, format, 0, format.length(), textDir, tempMt);
+ float moreWid = tempMt.getWholeWidth();
if (w + moreWid <= avail) {
ok = i + 1;
@@ -1528,40 +1533,18 @@
}
}
}
- MeasuredText.recycle(tempMt);
SpannableStringBuilder out = new SpannableStringBuilder(okFormat);
out.insert(0, text, 0, ok);
return out;
} finally {
- MeasuredText.recycle(mt);
- }
- }
-
- private static float setPara(MeasuredText mt, TextPaint paint,
- CharSequence text, int start, int end, TextDirectionHeuristic textDir) {
-
- mt.setPara(text, start, end, textDir);
-
- float width;
- Spanned sp = text instanceof Spanned ? (Spanned) text : null;
- int len = end - start;
- if (sp == null) {
- width = mt.addStyleRun(paint, len, null);
- } else {
- width = 0;
- int spanEnd;
- for (int spanStart = 0; spanStart < len; spanStart = spanEnd) {
- spanEnd = sp.nextSpanTransition(spanStart, len,
- MetricAffectingSpan.class);
- MetricAffectingSpan[] spans = sp.getSpans(
- spanStart, spanEnd, MetricAffectingSpan.class);
- spans = TextUtils.removeEmptySpans(spans, sp, MetricAffectingSpan.class);
- width += mt.addStyleRun(paint, spans, spanEnd - spanStart, null);
+ if (mt != null) {
+ mt.recycle();
+ }
+ if (tempMt != null) {
+ tempMt.recycle();
}
}
-
- return width;
}
// Returns true if the character's presence could affect RTL layout.
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 29baea1..80785fd 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -21,6 +21,7 @@
import android.provider.Settings;
import android.text.TextUtils;
+import java.util.HashMap;
import java.util.Map;
/**
@@ -33,6 +34,17 @@
public static final String FFLAG_PREFIX = "sys.fflag.";
public static final String FFLAG_OVERRIDE_PREFIX = FFLAG_PREFIX + "override.";
+ private static final Map<String, String> DEFAULT_FLAGS;
+ static {
+ DEFAULT_FLAGS = new HashMap<>();
+ DEFAULT_FLAGS.put("device_info_v2", "true");
+ DEFAULT_FLAGS.put("new_settings_suggestion", "true");
+ DEFAULT_FLAGS.put("settings_search_v2", "false");
+ DEFAULT_FLAGS.put("settings_app_info_v2", "false");
+ DEFAULT_FLAGS.put("settings_connected_device_v2", "false");
+ DEFAULT_FLAGS.put("settings_battery_v2", "false");
+ }
+
/**
* Whether or not a flag is enabled.
*
@@ -41,7 +53,7 @@
*/
public static boolean isEnabled(Context context, String feature) {
// Override precedence:
- // Settings.Global -> sys.fflag.override.* -> sys.fflag.*
+ // Settings.Global -> sys.fflag.override.* -> static list
// Step 1: check if feature flag is set in Settings.Global.
String value;
@@ -57,8 +69,8 @@
if (!TextUtils.isEmpty(value)) {
return Boolean.parseBoolean(value);
}
- // Step 3: check if feature flag has any default value. Flag name: sys.fflag.<feature>
- value = SystemProperties.get(FFLAG_PREFIX + feature);
+ // Step 3: check if feature flag has any default value.
+ value = getAllFeatureFlags().get(feature);
return Boolean.parseBoolean(value);
}
@@ -73,6 +85,6 @@
* Returns all feature flags in their raw form.
*/
public static Map<String, String> getAllFeatureFlags() {
- return null;
+ return DEFAULT_FLAGS;
}
}
diff --git a/core/java/android/util/KeyValueListParser.java b/core/java/android/util/KeyValueListParser.java
index d50395e..0a00794 100644
--- a/core/java/android/util/KeyValueListParser.java
+++ b/core/java/android/util/KeyValueListParser.java
@@ -149,6 +149,34 @@
}
/**
+ * Get the value for key as an integer array.
+ *
+ * The value should be encoded as "0:1:2:3:4"
+ *
+ * @param key The key to lookup.
+ * @param def The value to return if the key was not found.
+ * @return the int[] value associated with the key.
+ */
+ public int[] getIntArray(String key, int[] def) {
+ String value = mValues.get(key);
+ if (value != null) {
+ try {
+ String[] parts = value.split(":");
+ if (parts.length > 0) {
+ int[] ret = new int[parts.length];
+ for (int i = 0; i < parts.length; i++) {
+ ret[i] = Integer.parseInt(parts[i]);
+ }
+ return ret;
+ }
+ } catch (NumberFormatException e) {
+ // fallthrough
+ }
+ }
+ return def;
+ }
+
+ /**
* @return the number of keys.
*/
public int size() {
diff --git a/core/java/android/util/Pools.java b/core/java/android/util/Pools.java
index 70581be..f0b7e01 100644
--- a/core/java/android/util/Pools.java
+++ b/core/java/android/util/Pools.java
@@ -130,22 +130,29 @@
}
/**
- * Synchronized) pool of objects.
+ * Synchronized pool of objects.
*
* @param <T> The pooled type.
*/
public static class SynchronizedPool<T> extends SimplePool<T> {
- private final Object mLock = new Object();
+ private final Object mLock;
/**
* Creates a new instance.
*
* @param maxPoolSize The max pool size.
+ * @param lock an optional custom object to synchronize on
*
* @throws IllegalArgumentException If the max pool size is less than zero.
*/
- public SynchronizedPool(int maxPoolSize) {
+ public SynchronizedPool(int maxPoolSize, Object lock) {
super(maxPoolSize);
+ mLock = lock;
+ }
+
+ /** @see #SynchronizedPool(int, Object) */
+ public SynchronizedPool(int maxPoolSize) {
+ this(maxPoolSize, new Object());
}
@Override
diff --git a/core/java/android/util/StatsManager.java b/core/java/android/util/StatsManager.java
index 2bcd863..26a3c36 100644
--- a/core/java/android/util/StatsManager.java
+++ b/core/java/android/util/StatsManager.java
@@ -93,10 +93,11 @@
}
/**
- * Clients can request data with a binder call.
+ * Clients can request data with a binder call. This getter is destructive and also clears
+ * the retrieved metrics from statsd memory.
*
* @param configKey Configuration key to retrieve data from.
- * @return Serialized ConfigMetricsReport proto. Returns null on failure.
+ * @return Serialized ConfigMetricsReportList proto. Returns null on failure.
*/
@RequiresPermission(Manifest.permission.DUMP)
public byte[] getData(String configKey) {
@@ -115,6 +116,30 @@
}
}
+ /**
+ * Clients can request metadata for statsd. Will contain stats across all configurations but not
+ * the actual metrics themselves (metrics must be collected via {@link #getData(String)}.
+ * This getter is not destructive and will not reset any metrics/counters.
+ *
+ * @return Serialized StatsdStatsReport proto. Returns null on failure.
+ */
+ @RequiresPermission(Manifest.permission.DUMP)
+ public byte[] getMetadata() {
+ synchronized (this) {
+ try {
+ IStatsManager service = getIStatsManagerLocked();
+ if (service == null) {
+ Slog.d(TAG, "Failed to find statsd when getting metadata");
+ return null;
+ }
+ return service.getMetadata();
+ } catch (RemoteException e) {
+ Slog.d(TAG, "Failed to connecto statsd when getting metadata");
+ return null;
+ }
+ }
+ }
+
private class StatsdDeathRecipient implements IBinder.DeathRecipient {
@Override
public void binderDied() {
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 2ffa1c5..ba6b6cf 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -164,6 +164,7 @@
private long mLastFrameTimeNanos;
private long mFrameIntervalNanos;
private boolean mDebugPrintNextFrameTimeDelta;
+ private int mFPSDivisor = 1;
/**
* Contains information about the current frame for jank-tracking,
@@ -601,6 +602,11 @@
}
}
+ void setFPSDivisor(int divisor) {
+ if (divisor <= 0) divisor = 1;
+ mFPSDivisor = divisor;
+ }
+
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
@@ -643,6 +649,14 @@
return;
}
+ if (mFPSDivisor > 1) {
+ long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
+ if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
+ scheduleVsyncLocked();
+ return;
+ }
+ }
+
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/core/java/android/view/DisplayCutout.aidl
similarity index 64%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to core/java/android/view/DisplayCutout.aidl
index 4ccdea5..6d13b99 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/core/java/android/view/DisplayCutout.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
+/**
+ * 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
+ * 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,
@@ -14,11 +14,6 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+package android.view;
-import android.telephony.SubscriptionInfo;
-
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
-}
-
+parcelable DisplayCutout.ParcelableWrapper;
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
new file mode 100644
index 0000000..19cd42e
--- /dev/null
+++ b/core/java/android/view/DisplayCutout.java
@@ -0,0 +1,408 @@
+/*
+ * Copyright 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 android.view;
+
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import android.annotation.NonNull;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a part of the display that is not functional for displaying content.
+ *
+ * <p>{@code DisplayCutout} is immutable.
+ *
+ * @hide will become API
+ */
+public final class DisplayCutout {
+
+ private static final Rect ZERO_RECT = new Rect(0, 0, 0, 0);
+ private static final ArrayList<Point> EMPTY_LIST = new ArrayList<>();
+
+ /**
+ * An instance where {@link #hasCutout()} returns {@code false}.
+ *
+ * @hide
+ */
+ public static final DisplayCutout NO_CUTOUT =
+ new DisplayCutout(ZERO_RECT, ZERO_RECT, EMPTY_LIST);
+
+ private final Rect mSafeInsets;
+ private final Rect mBoundingRect;
+ private final List<Point> mBoundingPolygon;
+
+ /**
+ * Creates a DisplayCutout instance.
+ *
+ * NOTE: the Rects passed into this instance are not copied and MUST remain unchanged.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public DisplayCutout(Rect safeInsets, Rect boundingRect, List<Point> boundingPolygon) {
+ mSafeInsets = safeInsets != null ? safeInsets : ZERO_RECT;
+ mBoundingRect = boundingRect != null ? boundingRect : ZERO_RECT;
+ mBoundingPolygon = boundingPolygon != null ? boundingPolygon : EMPTY_LIST;
+ }
+
+ /**
+ * Returns whether there is a cutout.
+ *
+ * If false, the safe insets will all return zero, and the bounding box or polygon will be
+ * empty or outside the content view.
+ *
+ * @return {@code true} if there is a cutout, {@code false} otherwise
+ */
+ public boolean hasCutout() {
+ return !mSafeInsets.equals(ZERO_RECT);
+ }
+
+ /** Returns the inset from the top which avoids the display cutout. */
+ public int getSafeInsetTop() {
+ return mSafeInsets.top;
+ }
+
+ /** Returns the inset from the bottom which avoids the display cutout. */
+ public int getSafeInsetBottom() {
+ return mSafeInsets.bottom;
+ }
+
+ /** Returns the inset from the left which avoids the display cutout. */
+ public int getSafeInsetLeft() {
+ return mSafeInsets.left;
+ }
+
+ /** Returns the inset from the right which avoids the display cutout. */
+ public int getSafeInsetRight() {
+ return mSafeInsets.right;
+ }
+
+ /**
+ * Obtains the safe insets in a rect.
+ *
+ * @param out a rect which is set to the safe insets.
+ * @hide
+ */
+ public void getSafeInsets(@NonNull Rect out) {
+ out.set(mSafeInsets);
+ }
+
+ /**
+ * Obtains the bounding rect of the cutout.
+ *
+ * @param outRect is filled with the bounding rect of the cutout. Coordinates are relative
+ * to the top-left corner of the content view.
+ */
+ public void getBoundingRect(@NonNull Rect outRect) {
+ outRect.set(mBoundingRect);
+ }
+
+ /**
+ * Obtains the bounding polygon of the cutout.
+ *
+ * @param outPolygon is filled with a list of points representing the corners of a convex
+ * polygon which covers the cutout. Coordinates are relative to the
+ * top-left corner of the content view.
+ */
+ public void getBoundingPolygon(List<Point> outPolygon) {
+ outPolygon.clear();
+ for (int i = 0; i < mBoundingPolygon.size(); i++) {
+ outPolygon.add(new Point(mBoundingPolygon.get(i)));
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mSafeInsets.hashCode();
+ result = result * 31 + mBoundingRect.hashCode();
+ result = result * 31 + mBoundingPolygon.hashCode();
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o instanceof DisplayCutout) {
+ DisplayCutout c = (DisplayCutout) o;
+ return mSafeInsets.equals(c.mSafeInsets)
+ && mBoundingRect.equals(c.mBoundingRect)
+ && mBoundingPolygon.equals(c.mBoundingPolygon);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "DisplayCutout{insets=" + mSafeInsets
+ + " bounding=" + mBoundingRect
+ + "}";
+ }
+
+ /**
+ * Insets the reference frame of the cutout in the given directions.
+ *
+ * @return a copy of this instance which has been inset
+ * @hide
+ */
+ public DisplayCutout inset(int insetLeft, int insetTop, int insetRight, int insetBottom) {
+ if (mBoundingRect.isEmpty()
+ || insetLeft == 0 && insetTop == 0 && insetRight == 0 && insetBottom == 0) {
+ return this;
+ }
+
+ Rect safeInsets = new Rect(mSafeInsets);
+ Rect boundingRect = new Rect(mBoundingRect);
+ ArrayList<Point> boundingPolygon = new ArrayList<>();
+ getBoundingPolygon(boundingPolygon);
+
+ // Note: it's not really well defined what happens when the inset is negative, because we
+ // don't know if the safe inset needs to expand in general.
+ if (insetTop > 0 || safeInsets.top > 0) {
+ safeInsets.top = atLeastZero(safeInsets.top - insetTop);
+ }
+ if (insetBottom > 0 || safeInsets.bottom > 0) {
+ safeInsets.bottom = atLeastZero(safeInsets.bottom - insetBottom);
+ }
+ if (insetLeft > 0 || safeInsets.left > 0) {
+ safeInsets.left = atLeastZero(safeInsets.left - insetLeft);
+ }
+ if (insetRight > 0 || safeInsets.right > 0) {
+ safeInsets.right = atLeastZero(safeInsets.right - insetRight);
+ }
+
+ boundingRect.offset(-insetLeft, -insetTop);
+ offset(boundingPolygon, -insetLeft, -insetTop);
+
+ return new DisplayCutout(safeInsets, boundingRect, boundingPolygon);
+ }
+
+ /**
+ * Calculates the safe insets relative to the given reference frame.
+ *
+ * @return a copy of this instance with the safe insets calculated
+ * @hide
+ */
+ public DisplayCutout calculateRelativeTo(Rect frame) {
+ if (mBoundingRect.isEmpty() || !Rect.intersects(frame, mBoundingRect)) {
+ return NO_CUTOUT;
+ }
+
+ Rect boundingRect = new Rect(mBoundingRect);
+ ArrayList<Point> boundingPolygon = new ArrayList<>();
+ getBoundingPolygon(boundingPolygon);
+
+ return DisplayCutout.calculateRelativeTo(frame, boundingRect, boundingPolygon);
+ }
+
+ private static DisplayCutout calculateRelativeTo(Rect frame, Rect boundingRect,
+ ArrayList<Point> boundingPolygon) {
+ Rect safeRect = new Rect();
+ int bestArea = 0;
+ int bestVariant = 0;
+ for (int variant = ROTATION_0; variant <= ROTATION_270; variant++) {
+ int area = calculateInsetVariantArea(frame, boundingRect, variant, safeRect);
+ if (bestArea < area) {
+ bestArea = area;
+ bestVariant = variant;
+ }
+ }
+ calculateInsetVariantArea(frame, boundingRect, bestVariant, safeRect);
+ if (safeRect.isEmpty()) {
+ // The entire frame overlaps with the cutout.
+ safeRect.set(0, frame.height(), 0, 0);
+ } else {
+ // Convert safeRect to insets relative to frame. We're reusing the rect here to avoid
+ // an allocation.
+ safeRect.set(
+ Math.max(0, safeRect.left - frame.left),
+ Math.max(0, safeRect.top - frame.top),
+ Math.max(0, frame.right - safeRect.right),
+ Math.max(0, frame.bottom - safeRect.bottom));
+ }
+
+ boundingRect.offset(-frame.left, -frame.top);
+ offset(boundingPolygon, -frame.left, -frame.top);
+
+ return new DisplayCutout(safeRect, boundingRect, boundingPolygon);
+ }
+
+ private static int calculateInsetVariantArea(Rect frame, Rect boundingRect, int variant,
+ Rect outSafeRect) {
+ switch (variant) {
+ case ROTATION_0:
+ outSafeRect.set(frame.left, frame.top, frame.right, boundingRect.top);
+ break;
+ case ROTATION_90:
+ outSafeRect.set(frame.left, frame.top, boundingRect.left, frame.bottom);
+ break;
+ case ROTATION_180:
+ outSafeRect.set(frame.left, boundingRect.bottom, frame.right, frame.bottom);
+ break;
+ case ROTATION_270:
+ outSafeRect.set(boundingRect.right, frame.top, frame.right, frame.bottom);
+ break;
+ }
+
+ return outSafeRect.isEmpty() ? 0 : outSafeRect.width() * outSafeRect.height();
+ }
+
+ private static int atLeastZero(int value) {
+ return value < 0 ? 0 : value;
+ }
+
+ private static void offset(ArrayList<Point> points, int dx, int dy) {
+ for (int i = 0; i < points.size(); i++) {
+ points.get(i).offset(dx, dy);
+ }
+ }
+
+ /**
+ * Creates an instance from a bounding polygon.
+ *
+ * @hide
+ */
+ public static DisplayCutout fromBoundingPolygon(List<Point> points) {
+ Rect boundingRect = new Rect(Integer.MAX_VALUE, Integer.MAX_VALUE,
+ Integer.MIN_VALUE, Integer.MIN_VALUE);
+ ArrayList<Point> boundingPolygon = new ArrayList<>();
+
+ for (int i = 0; i < points.size(); i++) {
+ Point point = points.get(i);
+ boundingRect.left = Math.min(boundingRect.left, point.x);
+ boundingRect.right = Math.max(boundingRect.right, point.x);
+ boundingRect.top = Math.min(boundingRect.top, point.y);
+ boundingRect.bottom = Math.max(boundingRect.bottom, point.y);
+ boundingPolygon.add(new Point(point));
+ }
+
+ return new DisplayCutout(ZERO_RECT, boundingRect, boundingPolygon);
+ }
+
+ /**
+ * Helper class for passing {@link DisplayCutout} through binder.
+ *
+ * Needed, because {@code readFromParcel} cannot be used with immutable classes.
+ *
+ * @hide
+ */
+ public static final class ParcelableWrapper implements Parcelable {
+
+ private DisplayCutout mInner;
+
+ public ParcelableWrapper() {
+ this(NO_CUTOUT);
+ }
+
+ public ParcelableWrapper(DisplayCutout cutout) {
+ mInner = cutout;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ if (mInner == NO_CUTOUT) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(1);
+ out.writeTypedObject(mInner.mSafeInsets, flags);
+ out.writeTypedObject(mInner.mBoundingRect, flags);
+ out.writeTypedList(mInner.mBoundingPolygon, flags);
+ }
+ }
+
+ /**
+ * Similar to {@link Creator#createFromParcel(Parcel)}, but reads into an existing
+ * instance.
+ *
+ * Needed for AIDL out parameters.
+ */
+ public void readFromParcel(Parcel in) {
+ mInner = readCutout(in);
+ }
+
+ public static final Creator<ParcelableWrapper> CREATOR = new Creator<ParcelableWrapper>() {
+ @Override
+ public ParcelableWrapper createFromParcel(Parcel in) {
+ return new ParcelableWrapper(readCutout(in));
+ }
+
+ @Override
+ public ParcelableWrapper[] newArray(int size) {
+ return new ParcelableWrapper[size];
+ }
+ };
+
+ private static DisplayCutout readCutout(Parcel in) {
+ if (in.readInt() == 0) {
+ return NO_CUTOUT;
+ }
+
+ ArrayList<Point> boundingPolygon = new ArrayList<>();
+
+ Rect safeInsets = in.readTypedObject(Rect.CREATOR);
+ Rect boundingRect = in.readTypedObject(Rect.CREATOR);
+ in.readTypedList(boundingPolygon, Point.CREATOR);
+
+ return new DisplayCutout(safeInsets, boundingRect, boundingPolygon);
+ }
+
+ public DisplayCutout get() {
+ return mInner;
+ }
+
+ public void set(ParcelableWrapper cutout) {
+ mInner = cutout.get();
+ }
+
+ public void set(DisplayCutout cutout) {
+ mInner = cutout;
+ }
+
+ @Override
+ public int hashCode() {
+ return mInner.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof ParcelableWrapper
+ && mInner.equals(((ParcelableWrapper) o).mInner);
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(mInner);
+ }
+ }
+}
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 611cc63..07a57fb 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -23,6 +23,7 @@
import android.view.DragEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.DisplayCutout;
import com.android.internal.os.IResultReceiver;
import android.util.MergedConfiguration;
@@ -50,7 +51,8 @@
void resized(in Rect frame, in Rect overscanInsets, in Rect contentInsets,
in Rect visibleInsets, in Rect stableInsets, in Rect outsets, boolean reportDraw,
in MergedConfiguration newMergedConfiguration, in Rect backDropFrame,
- boolean forceLayout, boolean alwaysConsumeNavBar, int displayId);
+ boolean forceLayout, boolean alwaysConsumeNavBar, int displayId,
+ in DisplayCutout.ParcelableWrapper displayCutout);
void moved(int newX, int newY);
void dispatchAppVisibility(boolean visible);
void dispatchGetNewSurface();
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 29032a7..9e103a3 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -147,7 +147,6 @@
void exitKeyguardSecurely(IOnKeyguardExitResult callback);
boolean isKeyguardLocked();
boolean isKeyguardSecure();
- boolean inKeyguardRestrictedInputMode();
void dismissKeyguard(IKeyguardDismissCallback callback);
// Requires INTERACT_ACROSS_USERS_FULL permission
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 51d6514..ed167c8 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -22,6 +22,7 @@
import android.graphics.Region;
import android.os.Bundle;
import android.util.MergedConfiguration;
+import android.view.DisplayCutout;
import android.view.InputChannel;
import android.view.IWindow;
import android.view.IWindowId;
@@ -40,7 +41,8 @@
out InputChannel outInputChannel);
int addToDisplay(IWindow window, int seq, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, out Rect outContentInsets,
- out Rect outStableInsets, out Rect outOutsets, out InputChannel outInputChannel);
+ out Rect outStableInsets, out Rect outOutsets,
+ out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel);
int addWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs,
in int viewVisibility, out Rect outContentInsets, out Rect outStableInsets);
int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs,
@@ -96,6 +98,7 @@
int flags, out Rect outFrame, out Rect outOverscanInsets,
out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets,
out Rect outOutsets, out Rect outBackdropFrame,
+ out DisplayCutout.ParcelableWrapper displayCutout,
out MergedConfiguration outMergedConfiguration, out Surface outSurface);
/*
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index aa2f1c1..420a1bb 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -16,6 +16,9 @@
package android.view;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
import android.annotation.Size;
import android.graphics.Bitmap;
import android.graphics.GraphicBuffer;
@@ -23,6 +26,8 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.Process;
import android.os.UserHandle;
import android.util.Log;
@@ -36,12 +41,14 @@
* SurfaceControl
* @hide
*/
-public class SurfaceControl {
+public class SurfaceControl implements Parcelable {
private static final String TAG = "SurfaceControl";
private static native long nativeCreate(SurfaceSession session, String name,
int w, int h, int format, int flags, long parentObject, int windowType, int ownerUid)
throws OutOfResourcesException;
+ private static native long nativeReadFromParcel(Parcel in);
+ private static native void nativeWriteToParcel(long nativeObject, Parcel out);
private static native void nativeRelease(long nativeObject);
private static native void nativeDestroy(long nativeObject);
private static native void nativeDisconnect(long nativeObject);
@@ -55,8 +62,8 @@
private static native void nativeScreenshot(IBinder displayToken, Surface consumer,
Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
boolean allLayers, boolean useIdentityTransform);
- private static native void nativeCaptureLayers(IBinder layerHandleToken, Surface consumer,
- int rotation);
+ private static native GraphicBuffer nativeCaptureLayers(IBinder layerHandleToken,
+ Rect sourceCrop, float frameScale);
private static native long nativeCreateTransaction();
private static native long nativeGetNativeTransactionFinalizer();
@@ -574,6 +581,37 @@
mCloseGuard.open("release");
}
+ private SurfaceControl(Parcel in) {
+ mName = in.readString();
+ mNativeObject = nativeReadFromParcel(in);
+ if (mNativeObject == 0) {
+ throw new IllegalArgumentException("Couldn't read SurfaceControl from parcel=" + in);
+ }
+ mCloseGuard.open("release");
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mName);
+ nativeWriteToParcel(mNativeObject, dest);
+ }
+
+ public static final Creator<SurfaceControl> CREATOR
+ = new Creator<SurfaceControl>() {
+ public SurfaceControl createFromParcel(Parcel in) {
+ return new SurfaceControl(in);
+ }
+
+ public SurfaceControl[] newArray(int size) {
+ return new SurfaceControl[size];
+ }
+ };
+
@Override
protected void finalize() throws Throwable {
try {
@@ -664,7 +702,7 @@
*/
@Deprecated
public static void mergeToGlobalTransaction(Transaction t) {
- synchronized(sGlobalTransaction) {
+ synchronized(SurfaceControl.class) {
sGlobalTransaction.merge(t);
}
}
@@ -1142,22 +1180,35 @@
/**
* Like {@link SurfaceControl#screenshot(int, int, int, int, boolean)} but
- * includes all Surfaces in the screenshot.
+ * includes all Surfaces in the screenshot. This will also update the orientation so it
+ * sends the correct coordinates to SF based on the rotation value.
*
+ * @param sourceCrop The portion of the screen to capture into the Bitmap;
+ * caller may pass in 'new Rect()' if no cropping is desired.
* @param width The desired width of the returned bitmap; the raw
* screen will be scaled down to this size.
* @param height The desired height of the returned bitmap; the raw
* screen will be scaled down to this size.
+ * @param rotation Apply a custom clockwise rotation to the screenshot, i.e.
+ * Surface.ROTATION_0,90,180,270. Surfaceflinger will always take
+ * screenshots in its native portrait orientation by default, so this is
+ * useful for returning screenshots that are independent of device
+ * orientation.
* @return Returns a Bitmap containing the screen contents, or null
* if an error occurs. Make sure to call Bitmap.recycle() as soon as
* possible, once its content is not needed anymore.
*/
- public static Bitmap screenshot(int width, int height) {
+ public static Bitmap screenshot(Rect sourceCrop, int width, int height, int rotation) {
// TODO: should take the display as a parameter
IBinder displayToken = SurfaceControl.getBuiltInDisplay(
SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
- return nativeScreenshot(displayToken, new Rect(), width, height, 0, 0, true,
- false, Surface.ROTATION_0);
+ if (rotation == ROTATION_90 || rotation == ROTATION_270) {
+ rotation = (rotation == ROTATION_90) ? ROTATION_270 : ROTATION_90;
+ }
+
+ SurfaceControl.rotateCropForSF(sourceCrop, rotation);
+ return nativeScreenshot(displayToken, sourceCrop, width, height, 0, 0, true,
+ false, rotation);
}
private static void screenshot(IBinder display, Surface consumer, Rect sourceCrop,
@@ -1173,18 +1224,31 @@
minLayer, maxLayer, allLayers, useIdentityTransform);
}
+ private static void rotateCropForSF(Rect crop, int rot) {
+ if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
+ int tmp = crop.top;
+ crop.top = crop.left;
+ crop.left = tmp;
+ tmp = crop.right;
+ crop.right = crop.bottom;
+ crop.bottom = tmp;
+ }
+ }
+
/**
* Captures a layer and its children into the provided {@link Surface}.
*
* @param layerHandleToken The root layer to capture.
- * @param consumer The {@link Surface} to capture the layer into.
- * @param rotation Apply a custom clockwise rotation to the screenshot, i.e.
- * Surface.ROTATION_0,90,180,270. Surfaceflinger will always capture in its
- * native portrait orientation by default, so this is useful for returning
- * captures that are independent of device orientation.
+ * @param sourceCrop The portion of the root surface to capture; caller may pass in 'new
+ * Rect()' or null if no cropping is desired.
+ * @param frameScale The desired scale of the returned buffer; the raw
+ * screen will be scaled up/down.
+ *
+ * @return Returns a GraphicBuffer that contains the layer capture.
*/
- public static void captureLayers(IBinder layerHandleToken, Surface consumer, int rotation) {
- nativeCaptureLayers(layerHandleToken, consumer, rotation);
+ public static GraphicBuffer captureLayers(IBinder layerHandleToken, Rect sourceCrop,
+ float frameScale) {
+ return nativeCaptureLayers(layerHandleToken, sourceCrop, frameScale);
}
public static class Transaction implements Closeable {
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 7c76bab..0a69772 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -190,6 +190,17 @@
public static final String DEBUG_SHOW_NON_RECTANGULAR_CLIP_PROPERTY =
"debug.hwui.show_non_rect_clip";
+ /**
+ * Sets the FPS devisor to lower the FPS.
+ *
+ * Sets a positive integer as a divisor. 1 (the default value) menas the full FPS, and 2
+ * means half the full FPS.
+ *
+ *
+ * @hide
+ */
+ public static final String DEBUG_FPS_DIVISOR = "debug.hwui.fps_divisor";
+
static {
// Try to check OpenGL support early if possible.
isAvailable();
@@ -955,6 +966,9 @@
if (mInitialized) return;
mInitialized = true;
mAppContext = context.getApplicationContext();
+
+ // b/68769804: For low FPS experiments.
+ setFPSDivisor(SystemProperties.getInt(DEBUG_FPS_DIVISOR, 1));
initSched(renderProxy);
initGraphicsStats();
}
@@ -1007,6 +1021,13 @@
observer.mNative = null;
}
+ /** b/68769804: For low FPS experiments. */
+ public static void setFPSDivisor(int divisor) {
+ if (divisor <= 0) divisor = 1;
+ Choreographer.getInstance().setFPSDivisor(divisor);
+ nHackySetRTAnimationsEnabled(divisor == 1);
+ }
+
/** Not actually public - internal use only. This doc to make lint happy */
public static native void disableVsync();
@@ -1075,4 +1096,6 @@
private static native Bitmap nCreateHardwareBitmap(long renderNode, int width, int height);
private static native void nSetHighContrastText(boolean enabled);
+ // For temporary experimentation b/66945974
+ private static native void nHackySetRTAnimationsEnabled(boolean enabled);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e36a298..623759e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -893,6 +893,15 @@
*/
private static boolean sAutoFocusableOffUIThreadWontNotifyParents;
+ /**
+ * Prior to P things like setScaleX() allowed passing float values that were bogus such as
+ * Float.NaN. If the app is targetting P or later then passing these values will result in an
+ * exception being thrown. If the app is targetting an earlier SDK version, then we will
+ * silently clamp these values to avoid crashes elsewhere when the rendering code hits
+ * these bogus values.
+ */
+ private static boolean sThrowOnInvalidFloatProperties;
+
/** @hide */
@IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO})
@Retention(RetentionPolicy.SOURCE)
@@ -2929,6 +2938,7 @@
* 1 PFLAG3_TEMPORARY_DETACH
* 1 PFLAG3_NO_REVEAL_ON_FOCUS
* 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT
+ * 1 PFLAG3_SCREEN_READER_FOCUSABLE
* |-------|-------|-------|-------|
*/
@@ -3209,6 +3219,12 @@
*/
static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000;
+ /**
+ * Works like focusable for screen readers, but without the side effects on input focus.
+ * @see #setScreenReaderFocusable(boolean)
+ */
+ private static final int PFLAG3_SCREEN_READER_FOCUSABLE = 0x10000000;
+
/* End of masks for mPrivateFlags3 */
/**
@@ -4745,6 +4761,8 @@
sUseDefaultFocusHighlight = context.getResources().getBoolean(
com.android.internal.R.bool.config_useDefaultFocusHighlight);
+ sThrowOnInvalidFloatProperties = targetSdkVersion >= Build.VERSION_CODES.P;
+
sCompatibilityDone = true;
}
}
@@ -5344,6 +5362,11 @@
setDefaultFocusHighlightEnabled(a.getBoolean(attr, true));
}
break;
+ case R.styleable.View_screenReaderFocusable:
+ if (a.peekValue(attr) != null) {
+ setScreenReaderFocusable(a.getBoolean(attr, false));
+ }
+ break;
}
}
@@ -8394,6 +8417,7 @@
info.setEnabled(isEnabled());
info.setClickable(isClickable());
info.setFocusable(isFocusable());
+ info.setScreenReaderFocusable(isScreenReaderFocusable());
info.setFocused(isFocused());
info.setAccessibilityFocused(isAccessibilityFocused());
info.setSelected(isSelected());
@@ -10350,6 +10374,45 @@
}
/**
+ * Returns whether the view should be treated as a focusable unit by screen reader
+ * accessibility tools.
+ * @see #setScreenReaderFocusable(boolean)
+ *
+ * @return Whether the view should be treated as a focusable unit by screen reader.
+ */
+ public boolean isScreenReaderFocusable() {
+ return (mPrivateFlags3 & PFLAG3_SCREEN_READER_FOCUSABLE) != 0;
+ }
+
+ /**
+ * When screen readers (one type of accessibility tool) decide what should be read to the
+ * user, they typically look for input focusable ({@link #isFocusable()}) parents of
+ * non-focusable text items, and read those focusable parents and their non-focusable children
+ * as a unit. In some situations, this behavior is desirable for views that should not take
+ * input focus. Setting an item to be screen reader focusable requests that the view be
+ * treated as a unit by screen readers without any effect on input focusability. The default
+ * value of {@code false} lets screen readers use other signals, like focusable, to determine
+ * how to group items.
+ *
+ * @param screenReaderFocusable Whether the view should be treated as a unit by screen reader
+ * accessibility tools.
+ */
+ public void setScreenReaderFocusable(boolean screenReaderFocusable) {
+ int pflags3 = mPrivateFlags3;
+ if (screenReaderFocusable) {
+ pflags3 |= PFLAG3_SCREEN_READER_FOCUSABLE;
+ } else {
+ pflags3 &= ~PFLAG3_SCREEN_READER_FOCUSABLE;
+ }
+
+ if (pflags3 != mPrivateFlags3) {
+ mPrivateFlags3 = pflags3;
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ }
+ }
+
+ /**
* Find the nearest view in the specified direction that can take focus.
* This does not actually give focus to that view.
*
@@ -14220,7 +14283,7 @@
*/
public void setScaleX(float scaleX) {
if (scaleX != getScaleX()) {
- requireIsFinite(scaleX, "scaleX");
+ scaleX = sanitizeFloatPropertyValue(scaleX, "scaleX");
invalidateViewProperty(true, false);
mRenderNode.setScaleX(scaleX);
invalidateViewProperty(false, true);
@@ -14257,7 +14320,7 @@
*/
public void setScaleY(float scaleY) {
if (scaleY != getScaleY()) {
- requireIsFinite(scaleY, "scaleY");
+ scaleY = sanitizeFloatPropertyValue(scaleY, "scaleY");
invalidateViewProperty(true, false);
mRenderNode.setScaleY(scaleY);
invalidateViewProperty(false, true);
@@ -14807,13 +14870,41 @@
}
}
- private static void requireIsFinite(float transform, String propertyName) {
- if (Float.isNaN(transform)) {
- throw new IllegalArgumentException("Cannot set '" + propertyName + "' to Float.NaN");
+ private static float sanitizeFloatPropertyValue(float value, String propertyName) {
+ return sanitizeFloatPropertyValue(value, propertyName, -Float.MAX_VALUE, Float.MAX_VALUE);
+ }
+
+ private static float sanitizeFloatPropertyValue(float value, String propertyName,
+ float min, float max) {
+ // The expected "nothing bad happened" path
+ if (value >= min && value <= max) return value;
+
+ if (value < min || value == Float.NEGATIVE_INFINITY) {
+ if (sThrowOnInvalidFloatProperties) {
+ throw new IllegalArgumentException("Cannot set '" + propertyName + "' to "
+ + value + ", the value must be >= " + min);
+ }
+ return min;
}
- if (Float.isInfinite(transform)) {
- throw new IllegalArgumentException("Cannot set '" + propertyName + "' to infinity");
+
+ if (value > max || value == Float.POSITIVE_INFINITY) {
+ if (sThrowOnInvalidFloatProperties) {
+ throw new IllegalArgumentException("Cannot set '" + propertyName + "' to "
+ + value + ", the value must be <= " + max);
+ }
+ return max;
}
+
+ if (Float.isNaN(value)) {
+ if (sThrowOnInvalidFloatProperties) {
+ throw new IllegalArgumentException(
+ "Cannot set '" + propertyName + "' to Float.NaN");
+ }
+ return 0; // Unclear which direction this NaN went so... 0?
+ }
+
+ // Shouldn't be possible to reach this.
+ throw new IllegalStateException("How do you get here?? " + value);
}
/**
@@ -14902,7 +14993,7 @@
*/
public void setElevation(float elevation) {
if (elevation != getElevation()) {
- requireIsFinite(elevation, "elevation");
+ elevation = sanitizeFloatPropertyValue(elevation, "elevation");
invalidateViewProperty(true, false);
mRenderNode.setElevation(elevation);
invalidateViewProperty(false, true);
@@ -14995,7 +15086,7 @@
*/
public void setTranslationZ(float translationZ) {
if (translationZ != getTranslationZ()) {
- requireIsFinite(translationZ, "translationZ");
+ translationZ = sanitizeFloatPropertyValue(translationZ, "translationZ");
invalidateViewProperty(true, false);
mRenderNode.setTranslationZ(translationZ);
invalidateViewProperty(false, true);
@@ -25666,6 +25757,9 @@
*/
final Rect mStableInsets = new Rect();
+ final DisplayCutout.ParcelableWrapper mDisplayCutout =
+ new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
+
/**
* For windows that include areas that are not covered by real surface these are the outsets
* for real surface.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 929beae..122df93 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2591,7 +2591,7 @@
boolean alreadyDispatchedToNewTouchTarget = false;
if (!canceled && !intercepted) {
- // If the event is targeting accessiiblity focus we give it to the
+ // If the event is targeting accessibility focus we give it to the
// view that has accessibility focus and if it does not handle it
// we clear the flag and dispatch the event to all children as usual.
// We are looking up the accessibility focused host to avoid keeping
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e9509b7..0bae36b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -384,12 +384,15 @@
final Rect mPendingContentInsets = new Rect();
final Rect mPendingOutsets = new Rect();
final Rect mPendingBackDropFrame = new Rect();
+ final DisplayCutout.ParcelableWrapper mPendingDisplayCutout =
+ new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
boolean mPendingAlwaysConsumeNavBar;
final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
= new ViewTreeObserver.InternalInsetsInfo();
final Rect mDispatchContentInsets = new Rect();
final Rect mDispatchStableInsets = new Rect();
+ DisplayCutout mDispatchDisplayCutout = DisplayCutout.NO_CUTOUT;
private WindowInsets mLastWindowInsets;
@@ -730,7 +733,7 @@
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
- mAttachInfo.mOutsets, mInputChannel);
+ mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
} catch (RemoteException e) {
mAdded = false;
mView = null;
@@ -752,6 +755,7 @@
mPendingOverscanInsets.set(0, 0, 0, 0);
mPendingContentInsets.set(mAttachInfo.mContentInsets);
mPendingStableInsets.set(mAttachInfo.mStableInsets);
+ mPendingDisplayCutout.set(mAttachInfo.mDisplayCutout);
mPendingVisibleInsets.set(0, 0, 0, 0);
mAttachInfo.mAlwaysConsumeNavBar =
(res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR) != 0;
@@ -1544,15 +1548,20 @@
if (mLastWindowInsets == null || forceConstruct) {
mDispatchContentInsets.set(mAttachInfo.mContentInsets);
mDispatchStableInsets.set(mAttachInfo.mStableInsets);
+ mDispatchDisplayCutout = mAttachInfo.mDisplayCutout.get();
+
Rect contentInsets = mDispatchContentInsets;
Rect stableInsets = mDispatchStableInsets;
+ DisplayCutout displayCutout = mDispatchDisplayCutout;
// For dispatch we preserve old logic, but for direct requests from Views we allow to
// immediately use pending insets.
if (!forceConstruct
&& (!mPendingContentInsets.equals(contentInsets) ||
- !mPendingStableInsets.equals(stableInsets))) {
+ !mPendingStableInsets.equals(stableInsets) ||
+ !mPendingDisplayCutout.get().equals(displayCutout))) {
contentInsets = mPendingContentInsets;
stableInsets = mPendingStableInsets;
+ displayCutout = mPendingDisplayCutout.get();
}
Rect outsets = mAttachInfo.mOutsets;
if (outsets.left > 0 || outsets.top > 0 || outsets.right > 0 || outsets.bottom > 0) {
@@ -1563,7 +1572,7 @@
mLastWindowInsets = new WindowInsets(contentInsets,
null /* windowDecorInsets */, stableInsets,
mContext.getResources().getConfiguration().isScreenRound(),
- mAttachInfo.mAlwaysConsumeNavBar);
+ mAttachInfo.mAlwaysConsumeNavBar, displayCutout);
}
return mLastWindowInsets;
}
@@ -1730,6 +1739,9 @@
if (!mPendingStableInsets.equals(mAttachInfo.mStableInsets)) {
insetsChanged = true;
}
+ if (!mPendingDisplayCutout.equals(mAttachInfo.mDisplayCutout)) {
+ insetsChanged = true;
+ }
if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
@@ -1906,7 +1918,8 @@
+ " overscan=" + mPendingOverscanInsets.toShortString()
+ " content=" + mPendingContentInsets.toShortString()
+ " visible=" + mPendingVisibleInsets.toShortString()
- + " visible=" + mPendingStableInsets.toShortString()
+ + " stable=" + mPendingStableInsets.toShortString()
+ + " cutout=" + mPendingDisplayCutout.get().toString()
+ " outsets=" + mPendingOutsets.toShortString()
+ " surface=" + mSurface);
@@ -1931,6 +1944,8 @@
mAttachInfo.mVisibleInsets);
final boolean stableInsetsChanged = !mPendingStableInsets.equals(
mAttachInfo.mStableInsets);
+ final boolean cutoutChanged = !mPendingDisplayCutout.equals(
+ mAttachInfo.mDisplayCutout);
final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
final boolean surfaceSizeChanged = (relayoutResult
& WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
@@ -1955,6 +1970,14 @@
// Need to relayout with content insets.
contentInsetsChanged = true;
}
+ if (cutoutChanged) {
+ mAttachInfo.mDisplayCutout.set(mPendingDisplayCutout);
+ if (DEBUG_LAYOUT) {
+ Log.v(mTag, "DisplayCutout changing to: " + mAttachInfo.mDisplayCutout);
+ }
+ // Need to relayout with content insets.
+ contentInsetsChanged = true;
+ }
if (alwaysConsumeNavBarChanged) {
mAttachInfo.mAlwaysConsumeNavBar = mPendingAlwaysConsumeNavBar;
contentInsetsChanged = true;
@@ -2056,6 +2079,7 @@
mResizeMode = freeformResizing
? RESIZE_MODE_FREEFORM
: RESIZE_MODE_DOCKED_DIVIDER;
+ // TODO: Need cutout?
startDragResizing(mPendingBackDropFrame,
mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets,
mPendingStableInsets, mResizeMode);
@@ -3776,6 +3800,7 @@
&& mPendingOverscanInsets.equals(args.arg5)
&& mPendingContentInsets.equals(args.arg2)
&& mPendingStableInsets.equals(args.arg6)
+ && mPendingDisplayCutout.get().equals(args.arg9)
&& mPendingVisibleInsets.equals(args.arg3)
&& mPendingOutsets.equals(args.arg7)
&& mPendingBackDropFrame.equals(args.arg8)
@@ -3808,6 +3833,7 @@
|| !mPendingOverscanInsets.equals(args.arg5)
|| !mPendingContentInsets.equals(args.arg2)
|| !mPendingStableInsets.equals(args.arg6)
+ || !mPendingDisplayCutout.get().equals(args.arg9)
|| !mPendingVisibleInsets.equals(args.arg3)
|| !mPendingOutsets.equals(args.arg7);
@@ -3815,6 +3841,7 @@
mPendingOverscanInsets.set((Rect) args.arg5);
mPendingContentInsets.set((Rect) args.arg2);
mPendingStableInsets.set((Rect) args.arg6);
+ mPendingDisplayCutout.set((DisplayCutout) args.arg9);
mPendingVisibleInsets.set((Rect) args.arg3);
mPendingOutsets.set((Rect) args.arg7);
mPendingBackDropFrame.set((Rect) args.arg8);
@@ -6258,7 +6285,7 @@
(int) (mView.getMeasuredHeight() * appScale + 0.5f),
viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
- mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame,
+ mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
mPendingMergedConfiguration, mSurface);
mPendingAlwaysConsumeNavBar =
@@ -6541,7 +6568,8 @@
private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
- boolean alwaysConsumeNavBar, int displayId) {
+ boolean alwaysConsumeNavBar, int displayId,
+ DisplayCutout.ParcelableWrapper displayCutout) {
if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
+ " contentInsets=" + contentInsets.toShortString()
+ " visibleInsets=" + visibleInsets.toShortString()
@@ -6578,6 +6606,7 @@
args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
+ args.arg9 = displayCutout.get(); // DisplayCutout is immutable.
args.argi1 = forceLayout ? 1 : 0;
args.argi2 = alwaysConsumeNavBar ? 1 : 0;
args.argi3 = displayId;
@@ -7610,12 +7639,13 @@
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
- boolean alwaysConsumeNavBar, int displayId) {
+ boolean alwaysConsumeNavBar, int displayId,
+ DisplayCutout.ParcelableWrapper displayCutout) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
visibleInsets, stableInsets, outsets, reportDraw, mergedConfiguration,
- backDropFrame, forceLayout, alwaysConsumeNavBar, displayId);
+ backDropFrame, forceLayout, alwaysConsumeNavBar, displayId, displayCutout);
}
}
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 750931a..df124ac 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -17,6 +17,7 @@
package android.view;
+import android.annotation.NonNull;
import android.graphics.Rect;
/**
@@ -36,6 +37,7 @@
private Rect mStableInsets;
private Rect mTempRect;
private boolean mIsRound;
+ private DisplayCutout mDisplayCutout;
/**
* In multi-window we force show the navigation bar. Because we don't want that the surface size
@@ -47,6 +49,7 @@
private boolean mSystemWindowInsetsConsumed = false;
private boolean mWindowDecorInsetsConsumed = false;
private boolean mStableInsetsConsumed = false;
+ private boolean mCutoutConsumed = false;
private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0);
@@ -59,12 +62,12 @@
public static final WindowInsets CONSUMED;
static {
- CONSUMED = new WindowInsets(null, null, null, false, false);
+ CONSUMED = new WindowInsets(null, null, null, false, false, null);
}
/** @hide */
public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, Rect stableInsets,
- boolean isRound, boolean alwaysConsumeNavBar) {
+ boolean isRound, boolean alwaysConsumeNavBar, DisplayCutout displayCutout) {
mSystemWindowInsetsConsumed = systemWindowInsets == null;
mSystemWindowInsets = mSystemWindowInsetsConsumed ? EMPTY_RECT : systemWindowInsets;
@@ -76,6 +79,9 @@
mIsRound = isRound;
mAlwaysConsumeNavBar = alwaysConsumeNavBar;
+
+ mCutoutConsumed = displayCutout == null;
+ mDisplayCutout = mCutoutConsumed ? DisplayCutout.NO_CUTOUT : displayCutout;
}
/**
@@ -92,11 +98,13 @@
mStableInsetsConsumed = src.mStableInsetsConsumed;
mIsRound = src.mIsRound;
mAlwaysConsumeNavBar = src.mAlwaysConsumeNavBar;
+ mDisplayCutout = src.mDisplayCutout;
+ mCutoutConsumed = src.mCutoutConsumed;
}
/** @hide */
public WindowInsets(Rect systemWindowInsets) {
- this(systemWindowInsets, null, null, false, false);
+ this(systemWindowInsets, null, null, false, false, null);
}
/**
@@ -260,10 +268,35 @@
* @return true if any inset values are nonzero
*/
public boolean hasInsets() {
- return hasSystemWindowInsets() || hasWindowDecorInsets() || hasStableInsets();
+ return hasSystemWindowInsets() || hasWindowDecorInsets() || hasStableInsets()
+ || mDisplayCutout.hasCutout();
}
/**
+ * @return the display cutout
+ * @see DisplayCutout
+ * @hide pending API
+ */
+ @NonNull
+ public DisplayCutout getDisplayCutout() {
+ return mDisplayCutout;
+ }
+
+ /**
+ * Returns a copy of this WindowInsets with the cutout fully consumed.
+ *
+ * @return A modified copy of this WindowInsets
+ * @hide pending API
+ */
+ public WindowInsets consumeCutout() {
+ final WindowInsets result = new WindowInsets(this);
+ result.mDisplayCutout = DisplayCutout.NO_CUTOUT;
+ result.mCutoutConsumed = true;
+ return result;
+ }
+
+
+ /**
* Check if these insets have been fully consumed.
*
* <p>Insets are considered "consumed" if the applicable <code>consume*</code> methods
@@ -277,7 +310,8 @@
* @return true if the insets have been fully consumed.
*/
public boolean isConsumed() {
- return mSystemWindowInsetsConsumed && mWindowDecorInsetsConsumed && mStableInsetsConsumed;
+ return mSystemWindowInsetsConsumed && mWindowDecorInsetsConsumed && mStableInsetsConsumed
+ && mCutoutConsumed;
}
/**
@@ -495,7 +529,9 @@
public String toString() {
return "WindowInsets{systemWindowInsets=" + mSystemWindowInsets
+ " windowDecorInsets=" + mWindowDecorInsets
- + " stableInsets=" + mStableInsets +
- (isRound() ? " round}" : "}");
+ + " stableInsets=" + mStableInsets
+ + (mDisplayCutout.hasCutout() ? " cutout=" + mDisplayCutout : "")
+ + (isRound() ? " round" : "")
+ + "}";
}
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index eb5fc92..7c2c12f 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -604,8 +604,10 @@
public static final int TYPE_DRAG = FIRST_SYSTEM_WINDOW+16;
/**
- * Window type: panel that slides out from under the status bar
- * In multiuser systems shows on all users' windows.
+ * Window type: panel that slides out from over the status bar
+ * In multiuser systems shows on all users' windows. These windows
+ * are displayed on top of the stauts bar and any {@link #TYPE_STATUS_BAR_PANEL}
+ * windows.
* @hide
*/
public static final int TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17;
@@ -1266,6 +1268,35 @@
}, formatToHexString = true)
public int flags;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ flag = true,
+ value = {
+ LayoutParams.FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA,
+ })
+ @interface Flags2 {}
+
+ /**
+ * Window flag: allow placing the window within the area that overlaps with the
+ * display cutout.
+ *
+ * <p>
+ * The window must correctly position its contents to take the display cutout into account.
+ *
+ * @see DisplayCutout
+ * @hide for now
+ */
+ public static final long FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA = 0x00000001;
+
+ /**
+ * Various behavioral options/flags. Default is none.
+ *
+ * @see #FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA
+ * @hide for now
+ */
+ @Flags2 public long flags2;
+
/**
* If the window has requested hardware acceleration, but this is not
* allowed in the process it is in, then still render it as if it is
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index d785117..da5a1cd 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -23,8 +23,6 @@
import android.util.LongSparseArray;
import android.util.SparseArray;
-import com.android.internal.annotations.VisibleForTesting;
-
import java.util.ArrayList;
import java.util.List;
@@ -33,8 +31,7 @@
* It is updated when windows change or nodes change.
* @hide
*/
-@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-public final class AccessibilityCache {
+public class AccessibilityCache {
private static final String LOG_TAG = "AccessibilityCache";
@@ -329,6 +326,8 @@
final long oldParentId = oldInfo.getParentNodeId();
if (info.getParentNodeId() != oldParentId) {
clearSubTreeLocked(windowId, oldParentId);
+ } else {
+ oldInfo.recycle();
}
}
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 5adea66..1d19a9f 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -16,6 +16,7 @@
package android.view.accessibility;
+import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -23,6 +24,8 @@
import com.android.internal.util.BitUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
@@ -709,6 +712,38 @@
*/
public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 0x00000004;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "TYPE_" }, value = {
+ TYPE_VIEW_CLICKED,
+ TYPE_VIEW_LONG_CLICKED,
+ TYPE_VIEW_SELECTED,
+ TYPE_VIEW_FOCUSED,
+ TYPE_VIEW_TEXT_CHANGED,
+ TYPE_WINDOW_STATE_CHANGED,
+ TYPE_NOTIFICATION_STATE_CHANGED,
+ TYPE_VIEW_HOVER_ENTER,
+ TYPE_VIEW_HOVER_EXIT,
+ TYPE_TOUCH_EXPLORATION_GESTURE_START,
+ TYPE_TOUCH_EXPLORATION_GESTURE_END,
+ TYPE_WINDOW_CONTENT_CHANGED,
+ TYPE_VIEW_SCROLLED,
+ TYPE_VIEW_TEXT_SELECTION_CHANGED,
+ TYPE_ANNOUNCEMENT,
+ TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+ TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED,
+ TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
+ TYPE_GESTURE_DETECTION_START,
+ TYPE_GESTURE_DETECTION_END,
+ TYPE_TOUCH_INTERACTION_START,
+ TYPE_TOUCH_INTERACTION_END,
+ TYPE_WINDOWS_CHANGED,
+ TYPE_VIEW_CONTEXT_CLICKED,
+ TYPE_ASSIST_READING_CONTEXT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EventType {}
+
/**
* Mask for {@link AccessibilityEvent} all types.
*
@@ -741,7 +776,7 @@
private static final SynchronizedPool<AccessibilityEvent> sPool =
new SynchronizedPool<AccessibilityEvent>(MAX_POOL_SIZE);
- private int mEventType;
+ private @EventType int mEventType;
private CharSequence mPackageName;
private long mEventTime;
int mMovementGranularity;
@@ -833,7 +868,7 @@
*
* @return The event type.
*/
- public int getEventType() {
+ public @EventType int getEventType() {
return mEventType;
}
@@ -890,7 +925,7 @@
*
* @throws IllegalStateException If called from an AccessibilityService.
*/
- public void setEventType(int eventType) {
+ public void setEventType(@EventType int eventType) {
enforceNotSealed();
mEventType = eventType;
}
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index c3d6c69..d890f32 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -28,6 +28,8 @@
import android.util.LongSparseArray;
import android.util.SparseArray;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@@ -86,6 +88,12 @@
private static final LongSparseArray<AccessibilityInteractionClient> sClients =
new LongSparseArray<>();
+ private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache =
+ new SparseArray<>();
+
+ private static AccessibilityCache sAccessibilityCache =
+ new AccessibilityCache(new AccessibilityCache.AccessibilityNodeRefresher());
+
private final AtomicInteger mInteractionIdCounter = new AtomicInteger();
private final Object mInstanceLock = new Object();
@@ -100,12 +108,6 @@
private Message mSameThreadMessage;
- private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache =
- new SparseArray<>();
-
- private static final AccessibilityCache sAccessibilityCache =
- new AccessibilityCache(new AccessibilityCache.AccessibilityNodeRefresher());
-
/**
* @return The client for the current thread.
*/
@@ -133,6 +135,50 @@
}
}
+ /**
+ * Gets a cached accessibility service connection.
+ *
+ * @param connectionId The connection id.
+ * @return The cached connection if such.
+ */
+ public static IAccessibilityServiceConnection getConnection(int connectionId) {
+ synchronized (sConnectionCache) {
+ return sConnectionCache.get(connectionId);
+ }
+ }
+
+ /**
+ * Adds a cached accessibility service connection.
+ *
+ * @param connectionId The connection id.
+ * @param connection The connection.
+ */
+ public static void addConnection(int connectionId, IAccessibilityServiceConnection connection) {
+ synchronized (sConnectionCache) {
+ sConnectionCache.put(connectionId, connection);
+ }
+ }
+
+ /**
+ * Removes a cached accessibility service connection.
+ *
+ * @param connectionId The connection id.
+ */
+ public static void removeConnection(int connectionId) {
+ synchronized (sConnectionCache) {
+ sConnectionCache.remove(connectionId);
+ }
+ }
+
+ /**
+ * This method is only for testing. Replacing the cache is a generally terrible idea, but
+ * tests need to be able to verify this class's interactions with the cache
+ */
+ @VisibleForTesting
+ public static void setCache(AccessibilityCache cache) {
+ sAccessibilityCache = cache;
+ }
+
private AccessibilityInteractionClient() {
/* reducing constructor visibility */
}
@@ -300,7 +346,7 @@
if (success) {
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
- finalizeAndCacheAccessibilityNodeInfos(infos, connectionId);
+ finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, bypassCache);
if (infos != null && !infos.isEmpty()) {
for (int i = 1; i < infos.size(); i++) {
infos.get(i).recycle();
@@ -356,7 +402,7 @@
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
if (infos != null) {
- finalizeAndCacheAccessibilityNodeInfos(infos, connectionId);
+ finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, false);
return infos;
}
}
@@ -409,7 +455,7 @@
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
if (infos != null) {
- finalizeAndCacheAccessibilityNodeInfos(infos, connectionId);
+ finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, false);
return infos;
}
}
@@ -460,7 +506,7 @@
if (success) {
AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
interactionId);
- finalizeAndCacheAccessibilityNodeInfo(info, connectionId);
+ finalizeAndCacheAccessibilityNodeInfo(info, connectionId, false);
return info;
}
} else {
@@ -509,7 +555,7 @@
if (success) {
AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
interactionId);
- finalizeAndCacheAccessibilityNodeInfo(info, connectionId);
+ finalizeAndCacheAccessibilityNodeInfo(info, connectionId, false);
return info;
}
} else {
@@ -731,13 +777,17 @@
*
* @param info The info.
* @param connectionId The id of the connection to the system.
+ * @param bypassCache Whether or not to bypass the cache. The node is added to the cache if
+ * this value is {@code false}
*/
private void finalizeAndCacheAccessibilityNodeInfo(AccessibilityNodeInfo info,
- int connectionId) {
+ int connectionId, boolean bypassCache) {
if (info != null) {
info.setConnectionId(connectionId);
info.setSealed(true);
- sAccessibilityCache.add(info);
+ if (!bypassCache) {
+ sAccessibilityCache.add(info);
+ }
}
}
@@ -746,14 +796,16 @@
*
* @param infos The {@link AccessibilityNodeInfo}s.
* @param connectionId The id of the connection to the system.
+ * @param bypassCache Whether or not to bypass the cache. The nodes are added to the cache if
+ * this value is {@code false}
*/
private void finalizeAndCacheAccessibilityNodeInfos(List<AccessibilityNodeInfo> infos,
- int connectionId) {
+ int connectionId, boolean bypassCache) {
if (infos != null) {
final int infosCount = infos.size();
for (int i = 0; i < infosCount; i++) {
AccessibilityNodeInfo info = infos.get(i);
- finalizeAndCacheAccessibilityNodeInfo(info, connectionId);
+ finalizeAndCacheAccessibilityNodeInfo(info, connectionId, bypassCache);
}
}
}
@@ -773,41 +825,6 @@
}
/**
- * Gets a cached accessibility service connection.
- *
- * @param connectionId The connection id.
- * @return The cached connection if such.
- */
- public IAccessibilityServiceConnection getConnection(int connectionId) {
- synchronized (sConnectionCache) {
- return sConnectionCache.get(connectionId);
- }
- }
-
- /**
- * Adds a cached accessibility service connection.
- *
- * @param connectionId The connection id.
- * @param connection The connection.
- */
- public void addConnection(int connectionId, IAccessibilityServiceConnection connection) {
- synchronized (sConnectionCache) {
- sConnectionCache.put(connectionId, connection);
- }
- }
-
- /**
- * Removes a cached accessibility service connection.
- *
- * @param connectionId The connection id.
- */
- public void removeConnection(int connectionId) {
- synchronized (sConnectionCache) {
- sConnectionCache.remove(connectionId);
- }
- }
-
- /**
* Checks whether the infos are a fully connected tree with no duplicates.
*
* @param infos The result list to check.
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 9bdd3ff..faea920 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -635,6 +635,8 @@
private static final int BOOLEAN_PROPERTY_IMPORTANCE = 0x0040000;
+ private static final int BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE = 0x0080000;
+
private static final int BOOLEAN_PROPERTY_IS_SHOWING_HINT = 0x0100000;
/**
@@ -2321,6 +2323,37 @@
}
/**
+ * Returns whether the node is explicitly marked as a focusable unit by a screen reader. Note
+ * that {@code false} indicates that it is not explicitly marked, not that the node is not
+ * a focusable unit. Screen readers should generally used other signals, such as
+ * {@link #isFocusable()}, or the presence of text in a node, to determine what should receive
+ * focus.
+ *
+ * @return {@code true} if the node is specifically marked as a focusable unit for screen
+ * readers, {@code false} otherwise.
+ *
+ * @see View#isScreenReaderFocusable()
+ */
+ public boolean isScreenReaderFocusable() {
+ return getBooleanProperty(BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE);
+ }
+
+ /**
+ * Sets whether the node should be considered a focusable unit by a screen reader.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param screenReaderFocusable {@code true} if the node is a focusable unit for screen readers,
+ * {@code false} otherwise.
+ */
+ public void setScreenReaderFocusable(boolean screenReaderFocusable) {
+ setBooleanProperty(BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE, screenReaderFocusable);
+ }
+
+ /**
* Returns whether the node's text represents a hint for the user to enter text. It should only
* be {@code true} if the node has editable text.
*
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 547e0db..419aeb3 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -24,6 +24,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -36,6 +37,7 @@
import android.os.RemoteException;
import android.service.autofill.AutofillService;
import android.service.autofill.FillEventHistory;
+import android.service.autofill.UserData;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -45,6 +47,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.util.Preconditions;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -426,7 +429,7 @@
* @hide
*/
public AutofillManager(Context context, IAutoFillManager service) {
- mContext = context;
+ mContext = Preconditions.checkNotNull(context, "context cannot be null");
mService = service;
}
@@ -455,7 +458,7 @@
if (mSessionId != NO_SESSION) {
ensureServiceClientAddedIfNeededLocked();
- final AutofillClient client = getClientLocked();
+ final AutofillClient client = getClient();
if (client != null) {
try {
final boolean sessionWasRestored = mService.restoreSession(mSessionId,
@@ -1007,6 +1010,71 @@
}
/**
+ * Gets the user data used for <a href="#FieldsClassification">fields classification</a>.
+ *
+ * <p><b>Note:</b> This method should only be called by an app providing an autofill service.
+ *
+ * TODO(b/67867469):
+ * - proper javadoc
+ * - unhide / remove testApi
+ *
+ * @return value previously set by {@link #setUserData(UserData)} or {@code null} if it was
+ * reset or if the caller currently does not have an enabled autofill service for the user.
+ *
+ * @hide
+ */
+ @TestApi
+ @Nullable public UserData getUserData() {
+ try {
+ return mService.getUserData();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return null;
+ }
+ }
+
+ /**
+ * Sets the user data used for <a href="#FieldsClassification">fields classification</a>.
+ *
+ * <p><b>Note:</b> This method should only be called by an app providing an autofill service,
+ * and it's ignored if the caller currently doesn't have an enabled autofill service for
+ * the user.
+ *
+ * TODO(b/67867469):
+ * - proper javadoc
+ * - unhide / remove testApi
+ * - add unit tests:
+ * - call set / get / verify
+ *
+ * @hide
+ */
+ @TestApi
+ public void setUserData(@Nullable UserData userData) {
+ try {
+ mService.setUserData(userData);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * TODO(b/67867469):
+ * - proper javadoc
+ * - mention this method in other places
+ * - unhide / remove testApi
+ * @hide
+ */
+ @TestApi
+ public boolean isFieldClassificationEnabled() {
+ try {
+ return mService.isFieldClassificationEnabled();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return false;
+ }
+ }
+
+ /**
* Returns {@code true} if autofill is supported by the current device and
* is supported for this user.
*
@@ -1026,7 +1094,8 @@
}
}
- private AutofillClient getClientLocked() {
+ // Note: don't need to use locked suffix because mContext is final.
+ private AutofillClient getClient() {
final AutofillClient client = mContext.getAutofillClient();
if (client == null && sDebug) {
Log.d(TAG, "No AutofillClient for " + mContext.getPackageName() + " on context "
@@ -1089,16 +1158,16 @@
return;
}
try {
- final AutofillClient client = getClientLocked();
+ final AutofillClient client = getClient();
+ if (client == null) return; // NOTE: getClient() already logd it..
+
mSessionId = mService.startSession(mContext.getActivityToken(),
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
mCallback != null, flags, client.getComponentName());
if (mSessionId != NO_SESSION) {
mState = STATE_ACTIVE;
}
- if (client != null) {
- client.autofillCallbackResetableStateAvailable();
- }
+ client.autofillCallbackResetableStateAvailable();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1150,7 +1219,9 @@
try {
if (restartIfNecessary) {
- final AutofillClient client = getClientLocked();
+ final AutofillClient client = getClient();
+ if (client == null) return; // NOTE: getClient() already logd it..
+
final int newId = mService.updateOrRestartSession(mContext.getActivityToken(),
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
mCallback != null, flags, client.getComponentName(), mSessionId, action);
@@ -1158,9 +1229,7 @@
if (sDebug) Log.d(TAG, "Session restarted: " + mSessionId + "=>" + newId);
mSessionId = newId;
mState = (mSessionId == NO_SESSION) ? STATE_UNKNOWN : STATE_ACTIVE;
- if (client != null) {
- client.autofillCallbackResetableStateAvailable();
- }
+ client.autofillCallbackResetableStateAvailable();
}
} else {
mService.updateSession(mSessionId, id, bounds, value, action, flags,
@@ -1173,7 +1242,7 @@
}
private void ensureServiceClientAddedIfNeededLocked() {
- if (getClientLocked() == null) {
+ if (getClient() == null) {
return;
}
@@ -1256,7 +1325,7 @@
AutofillCallback callback = null;
synchronized (mLock) {
if (mSessionId == sessionId) {
- AutofillClient client = getClientLocked();
+ AutofillClient client = getClient();
if (client != null) {
if (client.autofillCallbackRequestShowFillUi(anchor, width, height,
@@ -1281,7 +1350,7 @@
Intent fillInIntent) {
synchronized (mLock) {
if (sessionId == mSessionId) {
- AutofillClient client = getClientLocked();
+ final AutofillClient client = getClient();
if (client != null) {
client.autofillCallbackAuthenticate(authenticationId, intent, fillInIntent);
}
@@ -1346,7 +1415,7 @@
return;
}
- final AutofillClient client = getClientLocked();
+ final AutofillClient client = getClient();
if (client == null) {
return;
}
@@ -1523,7 +1592,7 @@
// 1. If local and remote session id are off sync the UI would be stuck shown
// 2. There is a race between the user state being destroyed due the fill
// service being uninstalled and the UI being dismissed.
- AutofillClient client = getClientLocked();
+ AutofillClient client = getClient();
if (client != null) {
if (client.autofillCallbackRequestHideFillUi() && mCallback != null) {
callback = mCallback;
@@ -1553,7 +1622,7 @@
AutofillCallback callback = null;
synchronized (mLock) {
- if (mSessionId == sessionId && getClientLocked() != null) {
+ if (mSessionId == sessionId && getClient() != null) {
callback = mCallback;
}
}
@@ -1610,7 +1679,7 @@
* @return The view or {@code null} if view was not found
*/
private View findView(@NonNull AutofillId autofillId) {
- final AutofillClient client = getClientLocked();
+ final AutofillClient client = getClient();
if (client == null) {
return null;
@@ -1644,7 +1713,7 @@
pw.print(pfx); pw.print("sessionId: "); pw.println(mSessionId);
pw.print(pfx); pw.print("state: "); pw.println(getStateAsStringLocked());
pw.print(pfx); pw.print("context: "); pw.println(mContext);
- pw.print(pfx); pw.print("client: "); pw.println(getClientLocked());
+ pw.print(pfx); pw.print("client: "); pw.println(getClient());
pw.print(pfx); pw.print("enabled: "); pw.println(mEnabled);
pw.print(pfx); pw.print("hasService: "); pw.println(mService != null);
pw.print(pfx); pw.print("hasCallback: "); pw.println(mCallback != null);
@@ -1691,7 +1760,7 @@
}
private void post(Runnable runnable) {
- final AutofillClient client = getClientLocked();
+ final AutofillClient client = getClient();
if (client == null) {
if (sVerbose) Log.v(TAG, "ignoring post() because client is null");
return;
@@ -1774,7 +1843,7 @@
* @param trackedIds The views to be tracked
*/
TrackedViews(@Nullable AutofillId[] trackedIds) {
- final AutofillClient client = getClientLocked();
+ final AutofillClient client = getClient();
if (trackedIds != null && client != null) {
final boolean[] isVisible;
@@ -1815,7 +1884,7 @@
* @param isVisible visible if the view is visible in the view hierarchy.
*/
void notifyViewVisibilityChanged(@NonNull AutofillId id, boolean isVisible) {
- AutofillClient client = getClientLocked();
+ AutofillClient client = getClient();
if (sDebug) {
Log.d(TAG, "notifyViewVisibilityChanged(): id=" + id + " isVisible="
@@ -1852,7 +1921,7 @@
void onVisibleForAutofillLocked() {
// The visibility of the views might have changed while the client was not be visible,
// hence update the visibility state for all views.
- AutofillClient client = getClientLocked();
+ AutofillClient client = getClient();
ArraySet<AutofillId> updatedVisibleTrackedIds = null;
ArraySet<AutofillId> updatedInvisibleTrackedIds = null;
if (client != null) {
diff --git a/core/java/android/view/autofill/AutofillPopupWindow.java b/core/java/android/view/autofill/AutofillPopupWindow.java
index b4688bb..5cba21e 100644
--- a/core/java/android/view/autofill/AutofillPopupWindow.java
+++ b/core/java/android/view/autofill/AutofillPopupWindow.java
@@ -108,11 +108,12 @@
// symmetrically when the dropdown is below and above the anchor.
final View actualAnchor;
if (virtualBounds != null) {
+ final int[] mLocationOnScreen = new int[] {virtualBounds.left, virtualBounds.top};
actualAnchor = new View(anchor.getContext()) {
@Override
public void getLocationOnScreen(int[] location) {
- location[0] = virtualBounds.left;
- location[1] = virtualBounds.top;
+ location[0] = mLocationOnScreen[0];
+ location[1] = mLocationOnScreen[1];
}
@Override
@@ -178,6 +179,12 @@
virtualBounds.right, virtualBounds.bottom);
actualAnchor.setScrollX(anchor.getScrollX());
actualAnchor.setScrollY(anchor.getScrollY());
+
+ anchor.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
+ mLocationOnScreen[0] = mLocationOnScreen[0] - (scrollX - oldScrollX);
+ mLocationOnScreen[1] = mLocationOnScreen[1] - (scrollY - oldScrollY);
+ });
+ actualAnchor.setWillNotDraw(true);
} else {
actualAnchor = anchor;
}
diff --git a/core/java/android/view/autofill/AutofillValue.java b/core/java/android/view/autofill/AutofillValue.java
index 3beae11..8e649de 100644
--- a/core/java/android/view/autofill/AutofillValue.java
+++ b/core/java/android/view/autofill/AutofillValue.java
@@ -177,7 +177,7 @@
.append("[type=").append(mType)
.append(", value=");
if (isText()) {
- string.append(((CharSequence) mValue).length()).append("_chars");
+ Helper.appendRedacted(string, (CharSequence) mValue);
} else {
string.append(mValue);
}
diff --git a/core/java/android/view/autofill/Helper.java b/core/java/android/view/autofill/Helper.java
index 829e7f3..4b2c53c 100644
--- a/core/java/android/view/autofill/Helper.java
+++ b/core/java/android/view/autofill/Helper.java
@@ -16,11 +16,8 @@
package android.view.autofill;
-import android.os.Bundle;
-
-import java.util.Arrays;
-import java.util.Objects;
-import java.util.Set;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
/** @hide */
public final class Helper {
@@ -29,25 +26,37 @@
public static boolean sDebug = false;
public static boolean sVerbose = false;
- public static final String REDACTED = "[REDACTED]";
+ /**
+ * Appends {@code value} to the {@code builder} redacting its contents.
+ */
+ public static void appendRedacted(@NonNull StringBuilder builder,
+ @Nullable CharSequence value) {
+ builder.append(getRedacted(value));
+ }
- static StringBuilder append(StringBuilder builder, Bundle bundle) {
- if (bundle == null || !sDebug) {
+ /**
+ * Gets the redacted version of a value.
+ */
+ @NonNull
+ public static String getRedacted(@Nullable CharSequence value) {
+ return (value == null) ? "null" : value.length() + "_chars";
+ }
+
+ /**
+ * Appends {@code values} to the {@code builder} redacting its contents.
+ */
+ public static void appendRedacted(@NonNull StringBuilder builder, @Nullable String[] values) {
+ if (values == null) {
builder.append("N/A");
- } else if (!sVerbose) {
- builder.append(REDACTED);
- } else {
- final Set<String> keySet = bundle.keySet();
- builder.append("[Bundle with ").append(keySet.size()).append(" extras:");
- for (String key : keySet) {
- final Object value = bundle.get(key);
- builder.append(' ').append(key).append('=');
- builder.append((value instanceof Object[])
- ? Arrays.toString((Objects[]) value) : value);
- }
- builder.append(']');
+ return;
}
- return builder;
+ builder.append("[");
+ for (String value : values) {
+ builder.append(" '");
+ appendRedacted(builder, value);
+ builder.append("'");
+ }
+ builder.append(" ]");
}
private Helper() {
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index d6db3fe..f49aa5b 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -21,6 +21,7 @@
import android.os.Bundle;
import android.os.IBinder;
import android.service.autofill.FillEventHistory;
+import android.service.autofill.UserData;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
@@ -53,4 +54,7 @@
boolean isServiceSupported(int userId);
boolean isServiceEnabled(int userId, String packageName);
void onPendingSaveUi(int operation, IBinder token);
+ UserData getUserData();
+ void setUserData(in UserData userData);
+ boolean isFieldClassificationEnabled();
}
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index f0645b8..c69543f 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -67,6 +67,11 @@
final ResolveInfo mService;
/**
+ * IME only supports VR mode.
+ */
+ final boolean mIsVrOnly;
+
+ /**
* The unique string Id to identify the input method. This is generated
* from the input method component.
*/
@@ -149,6 +154,7 @@
PackageManager pm = context.getPackageManager();
String settingsActivityComponent = null;
+ boolean isVrOnly;
int isDefaultResId = 0;
XmlResourceParser parser = null;
@@ -179,6 +185,7 @@
com.android.internal.R.styleable.InputMethod);
settingsActivityComponent = sa.getString(
com.android.internal.R.styleable.InputMethod_settingsActivity);
+ isVrOnly = sa.getBoolean(com.android.internal.R.styleable.InputMethod_isVrOnly, false);
isDefaultResId = sa.getResourceId(
com.android.internal.R.styleable.InputMethod_isDefault, 0);
supportsSwitchingToNextInputMethod = sa.getBoolean(
@@ -254,6 +261,8 @@
mIsDefaultResId = isDefaultResId;
mIsAuxIme = isAuxIme;
mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
+ // TODO(b/68948291): remove this meta-data before release.
+ mIsVrOnly = isVrOnly || service.serviceInfo.metaData.getBoolean("isVrOnly", false);
}
InputMethodInfo(Parcel source) {
@@ -262,6 +271,7 @@
mIsDefaultResId = source.readInt();
mIsAuxIme = source.readInt() == 1;
mSupportsSwitchingToNextInputMethod = source.readInt() == 1;
+ mIsVrOnly = source.readBoolean();
mService = ResolveInfo.CREATOR.createFromParcel(source);
mSubtypes = new InputMethodSubtypeArray(source);
mForceDefault = false;
@@ -274,7 +284,8 @@
CharSequence label, String settingsActivity) {
this(buildDummyResolveInfo(packageName, className, label), false /* isAuxIme */,
settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
- false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */);
+ false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
+ false /* isVrOnly */);
}
/**
@@ -285,7 +296,7 @@
String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId,
boolean forceDefault) {
this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
- true /* supportsSwitchingToNextInputMethod */);
+ true /* supportsSwitchingToNextInputMethod */, false /* isVrOnly */);
}
/**
@@ -294,7 +305,7 @@
*/
public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity,
List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
- boolean supportsSwitchingToNextInputMethod) {
+ boolean supportsSwitchingToNextInputMethod, boolean isVrOnly) {
final ServiceInfo si = ri.serviceInfo;
mService = ri;
mId = new ComponentName(si.packageName, si.name).flattenToShortString();
@@ -304,6 +315,7 @@
mSubtypes = new InputMethodSubtypeArray(subtypes);
mForceDefault = forceDefault;
mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
+ mIsVrOnly = isVrOnly;
}
private static ResolveInfo buildDummyResolveInfo(String packageName, String className,
@@ -398,6 +410,14 @@
}
/**
+ * Returns true if IME supports VR mode only.
+ * @hide
+ */
+ public boolean isVrOnly() {
+ return mIsVrOnly;
+ }
+
+ /**
* Return the count of the subtypes of Input Method.
*/
public int getSubtypeCount() {
@@ -444,6 +464,7 @@
public void dump(Printer pw, String prefix) {
pw.println(prefix + "mId=" + mId
+ " mSettingsActivityName=" + mSettingsActivityName
+ + " mIsVrOnly=" + mIsVrOnly
+ " mSupportsSwitchingToNextInputMethod=" + mSupportsSwitchingToNextInputMethod);
pw.println(prefix + "mIsDefaultResId=0x"
+ Integer.toHexString(mIsDefaultResId));
@@ -509,6 +530,7 @@
dest.writeInt(mIsDefaultResId);
dest.writeInt(mIsAuxIme ? 1 : 0);
dest.writeInt(mSupportsSwitchingToNextInputMethod ? 1 : 0);
+ dest.writeBoolean(mIsVrOnly);
mService.writeToParcel(dest, flags);
mSubtypes.writeToParcel(dest);
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 92d1de8..4d96733 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -697,6 +697,19 @@
}
}
+ /**
+ * Returns a list of VR InputMethod currently installed.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
+ public List<InputMethodInfo> getVrInputMethodList() {
+ try {
+ return mService.getVrInputMethodList();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
public List<InputMethodInfo> getEnabledInputMethodList() {
try {
return mService.getEnabledInputMethodList();
diff --git a/core/java/android/view/inputmethod/InputMethodManagerInternal.java b/core/java/android/view/inputmethod/InputMethodManagerInternal.java
index 77df4e3..e13813e 100644
--- a/core/java/android/view/inputmethod/InputMethodManagerInternal.java
+++ b/core/java/android/view/inputmethod/InputMethodManagerInternal.java
@@ -16,6 +16,8 @@
package android.view.inputmethod;
+import android.content.ComponentName;
+
/**
* Input method manager local system service interface.
*
@@ -37,4 +39,9 @@
* Hides the current input method, if visible.
*/
void hideCurrentInputMethod();
+
+ /**
+ * Switches to VR InputMethod defined in the packageName of {@param componentName}.
+ */
+ void startVrInputMethodNoCheck(ComponentName componentName);
}
diff --git a/core/java/android/view/textclassifier/EntityConfidence.java b/core/java/android/view/textclassifier/EntityConfidence.java
index 0589d204..19660d9 100644
--- a/core/java/android/view/textclassifier/EntityConfidence.java
+++ b/core/java/android/view/textclassifier/EntityConfidence.java
@@ -18,13 +18,12 @@
import android.annotation.FloatRange;
import android.annotation.NonNull;
+import android.util.ArrayMap;
import com.android.internal.util.Preconditions;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -36,42 +35,43 @@
*/
final class EntityConfidence<T> {
- private final Map<T, Float> mEntityConfidence = new HashMap<>();
-
- private final Comparator<T> mEntityComparator = (e1, e2) -> {
- float score1 = mEntityConfidence.get(e1);
- float score2 = mEntityConfidence.get(e2);
- if (score1 > score2) {
- return -1;
- }
- if (score1 < score2) {
- return 1;
- }
- return 0;
- };
+ private final ArrayMap<T, Float> mEntityConfidence = new ArrayMap<>();
+ private final ArrayList<T> mSortedEntities = new ArrayList<>();
EntityConfidence() {}
EntityConfidence(@NonNull EntityConfidence<T> source) {
Preconditions.checkNotNull(source);
mEntityConfidence.putAll(source.mEntityConfidence);
+ mSortedEntities.addAll(source.mSortedEntities);
}
/**
- * Sets an entity type for the classified text and assigns a confidence score.
+ * Constructs an EntityConfidence from a map of entity to confidence.
*
- * @param confidenceScore a value from 0 (low confidence) to 1 (high confidence).
- * 0 implies the entity does not exist for the classified text.
- * Values greater than 1 are clamped to 1.
+ * Map entries that have 0 confidence are removed, and values greater than 1 are clamped to 1.
+ *
+ * @param source a map from entity to a confidence value in the range 0 (low confidence) to
+ * 1 (high confidence).
*/
- public void setEntityType(
- @NonNull T type, @FloatRange(from = 0.0, to = 1.0) float confidenceScore) {
- Preconditions.checkNotNull(type);
- if (confidenceScore > 0) {
- mEntityConfidence.put(type, Math.min(1, confidenceScore));
- } else {
- mEntityConfidence.remove(type);
+ EntityConfidence(@NonNull Map<T, Float> source) {
+ Preconditions.checkNotNull(source);
+
+ // Prune non-existent entities and clamp to 1.
+ mEntityConfidence.ensureCapacity(source.size());
+ for (Map.Entry<T, Float> it : source.entrySet()) {
+ if (it.getValue() <= 0) continue;
+ mEntityConfidence.put(it.getKey(), Math.min(1, it.getValue()));
}
+
+ // Create a list of entities sorted by decreasing confidence for getEntities().
+ mSortedEntities.ensureCapacity(mEntityConfidence.size());
+ mSortedEntities.addAll(mEntityConfidence.keySet());
+ mSortedEntities.sort((e1, e2) -> {
+ float score1 = mEntityConfidence.get(e1);
+ float score2 = mEntityConfidence.get(e2);
+ return Float.compare(score2, score1);
+ });
}
/**
@@ -80,10 +80,7 @@
*/
@NonNull
public List<T> getEntities() {
- List<T> entities = new ArrayList<>(mEntityConfidence.size());
- entities.addAll(mEntityConfidence.keySet());
- entities.sort(mEntityComparator);
- return Collections.unmodifiableList(entities);
+ return Collections.unmodifiableList(mSortedEntities);
}
/**
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 2779aa2..7ffbf63 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -24,6 +24,7 @@
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.LocaleList;
+import android.util.ArrayMap;
import android.view.View.OnClickListener;
import android.view.textclassifier.TextClassifier.EntityType;
@@ -31,18 +32,21 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
+import java.util.Map;
/**
* Information for generating a widget to handle classified text.
*
* <p>A TextClassification object contains icons, labels, onClickListeners and intents that may
- * be used to build a widget that can be used to act on classified text.
+ * be used to build a widget that can be used to act on classified text. There is the concept of a
+ * <i>primary action</i> and other <i>secondary actions</i>.
*
* <p>e.g. building a view that, when clicked, shares the classified text with the preferred app:
*
* <pre>{@code
* // Called preferably outside the UiThread.
- * TextClassification classification = textClassifier.classifyText(allText, 10, 25, null);
+ * TextClassification classification = textClassifier.classifyText(allText, 10, 25);
*
* // Called on the UiThread.
* Button button = new Button(context);
@@ -55,17 +59,24 @@
*
* <pre>{@code
* // Called preferably outside the UiThread.
- * final TextClassification classification = textClassifier.classifyText(allText, 10, 25, null);
+ * final TextClassification classification = textClassifier.classifyText(allText, 10, 25);
*
* // Called on the UiThread.
* view.startActionMode(new ActionMode.Callback() {
*
* public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- * for (int i = 0; i < classification.getActionCount(); i++) {
- * if (thisAppHasPermissionToInvokeIntent(classification.getIntent(i))) {
- * menu.add(Menu.NONE, i, 20, classification.getLabel(i))
- * .setIcon(classification.getIcon(i))
- * .setIntent(classification.getIntent(i));
+ * // Add the "primary" action.
+ * if (thisAppHasPermissionToInvokeIntent(classification.getIntent())) {
+ * menu.add(Menu.NONE, 0, 20, classification.getLabel())
+ * .setIcon(classification.getIcon())
+ * .setIntent(classification.getIntent());
+ * }
+ * // Add the "secondary" actions.
+ * for (int i = 0; i < classification.getSecondaryActionsCount(); i++) {
+ * if (thisAppHasPermissionToInvokeIntent(classification.getSecondaryIntent(i))) {
+ * menu.add(Menu.NONE, i + 1, 20, classification.getSecondaryLabel(i))
+ * .setIcon(classification.getSecondaryIcon(i))
+ * .setIntent(classification.getSecondaryIntent(i));
* }
* }
* return true;
@@ -89,36 +100,43 @@
static final TextClassification EMPTY = new TextClassification.Builder().build();
@NonNull private final String mText;
- @NonNull private final List<Drawable> mIcons;
- @NonNull private final List<String> mLabels;
- @NonNull private final List<Intent> mIntents;
- @NonNull private final List<OnClickListener> mOnClickListeners;
+ @Nullable private final Drawable mPrimaryIcon;
+ @Nullable private final String mPrimaryLabel;
+ @Nullable private final Intent mPrimaryIntent;
+ @Nullable private final OnClickListener mPrimaryOnClickListener;
+ @NonNull private final List<Drawable> mSecondaryIcons;
+ @NonNull private final List<String> mSecondaryLabels;
+ @NonNull private final List<Intent> mSecondaryIntents;
+ @NonNull private final List<OnClickListener> mSecondaryOnClickListeners;
@NonNull private final EntityConfidence<String> mEntityConfidence;
- @NonNull private final List<String> mEntities;
- private int mLogType;
- @NonNull private final String mVersionInfo;
+ @NonNull private final String mSignature;
private TextClassification(
@Nullable String text,
- @NonNull List<Drawable> icons,
- @NonNull List<String> labels,
- @NonNull List<Intent> intents,
- @NonNull List<OnClickListener> onClickListeners,
- @NonNull EntityConfidence<String> entityConfidence,
- int logType,
- @NonNull String versionInfo) {
- Preconditions.checkArgument(labels.size() == intents.size());
- Preconditions.checkArgument(icons.size() == intents.size());
- Preconditions.checkArgument(onClickListeners.size() == intents.size());
+ @Nullable Drawable primaryIcon,
+ @Nullable String primaryLabel,
+ @Nullable Intent primaryIntent,
+ @Nullable OnClickListener primaryOnClickListener,
+ @NonNull List<Drawable> secondaryIcons,
+ @NonNull List<String> secondaryLabels,
+ @NonNull List<Intent> secondaryIntents,
+ @NonNull List<OnClickListener> secondaryOnClickListeners,
+ @NonNull Map<String, Float> entityConfidence,
+ @NonNull String signature) {
+ Preconditions.checkArgument(secondaryLabels.size() == secondaryIntents.size());
+ Preconditions.checkArgument(secondaryIcons.size() == secondaryIntents.size());
+ Preconditions.checkArgument(secondaryOnClickListeners.size() == secondaryIntents.size());
mText = text;
- mIcons = icons;
- mLabels = labels;
- mIntents = intents;
- mOnClickListeners = onClickListeners;
+ mPrimaryIcon = primaryIcon;
+ mPrimaryLabel = primaryLabel;
+ mPrimaryIntent = primaryIntent;
+ mPrimaryOnClickListener = primaryOnClickListener;
+ mSecondaryIcons = secondaryIcons;
+ mSecondaryLabels = secondaryLabels;
+ mSecondaryIntents = secondaryIntents;
+ mSecondaryOnClickListeners = secondaryOnClickListeners;
mEntityConfidence = new EntityConfidence<>(entityConfidence);
- mEntities = mEntityConfidence.getEntities();
- mLogType = logType;
- mVersionInfo = versionInfo;
+ mSignature = signature;
}
/**
@@ -134,7 +152,7 @@
*/
@IntRange(from = 0)
public int getEntityCount() {
- return mEntities.size();
+ return mEntityConfidence.getEntities().size();
}
/**
@@ -146,7 +164,7 @@
*/
@NonNull
public @EntityType String getEntity(int index) {
- return mEntities.get(index);
+ return mEntityConfidence.getEntities().get(index);
}
/**
@@ -160,130 +178,160 @@
}
/**
- * Returns the number of actions that are available to act on the classified text.
- * @see #getIntent(int)
- * @see #getLabel(int)
- * @see #getIcon(int)
- * @see #getOnClickListener(int)
+ * Returns the number of <i>secondary</i> actions that are available to act on the classified
+ * text.
+ *
+ * <p><strong>Note: </strong> that there may or may not be a <i>primary</i> action.
+ *
+ * @see #getSecondaryIntent(int)
+ * @see #getSecondaryLabel(int)
+ * @see #getSecondaryIcon(int)
+ * @see #getSecondaryOnClickListener(int)
*/
@IntRange(from = 0)
- public int getActionCount() {
- return mIntents.size();
+ public int getSecondaryActionsCount() {
+ return mSecondaryIntents.size();
}
/**
- * Returns one of the icons that maybe rendered on a widget used to act on the classified text.
+ * Returns one of the <i>secondary</i> icons that maybe rendered on a widget used to act on the
+ * classified text.
+ *
* @param index Index of the action to get the icon for.
+ *
* @throws IndexOutOfBoundsException if the specified index is out of range.
- * @see #getActionCount() for the number of entities available.
- * @see #getIntent(int)
- * @see #getLabel(int)
- * @see #getOnClickListener(int)
+ *
+ * @see #getSecondaryActionsCount() for the number of actions available.
+ * @see #getSecondaryIntent(int)
+ * @see #getSecondaryLabel(int)
+ * @see #getSecondaryOnClickListener(int)
+ * @see #getIcon()
*/
@Nullable
- public Drawable getIcon(int index) {
- return mIcons.get(index);
+ public Drawable getSecondaryIcon(int index) {
+ return mSecondaryIcons.get(index);
}
/**
- * Returns an icon for the default intent that may be rendered on a widget used to act on the
- * classified text.
+ * Returns an icon for the <i>primary</i> intent that may be rendered on a widget used to act
+ * on the classified text.
+ *
+ * @see #getSecondaryIcon(int)
*/
@Nullable
public Drawable getIcon() {
- return mIcons.isEmpty() ? null : mIcons.get(0);
+ return mPrimaryIcon;
}
/**
- * Returns one of the labels that may be rendered on a widget used to act on the classified
- * text.
+ * Returns one of the <i>secondary</i> labels that may be rendered on a widget used to act on
+ * the classified text.
+ *
* @param index Index of the action to get the label for.
+ *
* @throws IndexOutOfBoundsException if the specified index is out of range.
- * @see #getActionCount()
- * @see #getIntent(int)
- * @see #getIcon(int)
- * @see #getOnClickListener(int)
+ *
+ * @see #getSecondaryActionsCount()
+ * @see #getSecondaryIntent(int)
+ * @see #getSecondaryIcon(int)
+ * @see #getSecondaryOnClickListener(int)
+ * @see #getLabel()
*/
@Nullable
- public CharSequence getLabel(int index) {
- return mLabels.get(index);
+ public CharSequence getSecondaryLabel(int index) {
+ return mSecondaryLabels.get(index);
}
/**
- * Returns a label for the default intent that may be rendered on a widget used to act on the
- * classified text.
+ * Returns a label for the <i>primary</i> intent that may be rendered on a widget used to act
+ * on the classified text.
+ *
+ * @see #getSecondaryLabel(int)
*/
@Nullable
public CharSequence getLabel() {
- return mLabels.isEmpty() ? null : mLabels.get(0);
+ return mPrimaryLabel;
}
/**
- * Returns one of the intents that may be fired to act on the classified text.
+ * Returns one of the <i>secondary</i> intents that may be fired to act on the classified text.
+ *
* @param index Index of the action to get the intent for.
+ *
* @throws IndexOutOfBoundsException if the specified index is out of range.
- * @see #getActionCount()
- * @see #getLabel(int)
- * @see #getIcon(int)
- * @see #getOnClickListener(int)
+ *
+ * @see #getSecondaryActionsCount()
+ * @see #getSecondaryLabel(int)
+ * @see #getSecondaryIcon(int)
+ * @see #getSecondaryOnClickListener(int)
+ * @see #getIntent()
*/
@Nullable
- public Intent getIntent(int index) {
- return mIntents.get(index);
+ public Intent getSecondaryIntent(int index) {
+ return mSecondaryIntents.get(index);
}
/**
- * Returns the default intent that may be fired to act on the classified text.
+ * Returns the <i>primary</i> intent that may be fired to act on the classified text.
+ *
+ * @see #getSecondaryIntent(int)
*/
@Nullable
public Intent getIntent() {
- return mIntents.isEmpty() ? null : mIntents.get(0);
+ return mPrimaryIntent;
}
/**
- * Returns one of the OnClickListeners that may be triggered to act on the classified text.
+ * Returns one of the <i>secondary</i> OnClickListeners that may be triggered to act on the
+ * classified text.
+ *
* @param index Index of the action to get the click listener for.
+ *
* @throws IndexOutOfBoundsException if the specified index is out of range.
- * @see #getActionCount()
- * @see #getIntent(int)
- * @see #getLabel(int)
- * @see #getIcon(int)
+ *
+ * @see #getSecondaryActionsCount()
+ * @see #getSecondaryIntent(int)
+ * @see #getSecondaryLabel(int)
+ * @see #getSecondaryIcon(int)
+ * @see #getOnClickListener()
*/
@Nullable
- public OnClickListener getOnClickListener(int index) {
- return mOnClickListeners.get(index);
+ public OnClickListener getSecondaryOnClickListener(int index) {
+ return mSecondaryOnClickListeners.get(index);
}
/**
- * Returns the default OnClickListener that may be triggered to act on the classified text.
+ * Returns the <i>primary</i> OnClickListener that may be triggered to act on the classified
+ * text.
+ *
+ * @see #getSecondaryOnClickListener(int)
*/
@Nullable
public OnClickListener getOnClickListener() {
- return mOnClickListeners.isEmpty() ? null : mOnClickListeners.get(0);
+ return mPrimaryOnClickListener;
}
/**
- * Returns the MetricsLogger subtype for the action that is performed for this result.
- * @hide
- */
- public int getLogType() {
- return mLogType;
- }
-
- /**
- * Returns information about the classifier model used to generate this TextClassification.
- * @hide
+ * Returns the signature for this object.
+ * The TextClassifier that generates this object may use it as a way to internally identify
+ * this object.
*/
@NonNull
- public String getVersionInfo() {
- return mVersionInfo;
+ public String getSignature() {
+ return mSignature;
}
@Override
public String toString() {
- return String.format("TextClassification {"
- + "text=%s, entities=%s, labels=%s, intents=%s}",
- mText, mEntityConfidence, mLabels, mIntents);
+ return String.format(Locale.US, "TextClassification {"
+ + "text=%s, entities=%s, "
+ + "primaryLabel=%s, secondaryLabels=%s, "
+ + "primaryIntent=%s, secondaryIntents=%s, "
+ + "signature=%s}",
+ mText, mEntityConfidence,
+ mPrimaryLabel, mSecondaryLabels,
+ mPrimaryIntent, mSecondaryIntents,
+ mSignature);
}
/**
@@ -302,18 +350,33 @@
/**
* Builder for building {@link TextClassification} objects.
+ *
+ * <p>e.g.
+ *
+ * <pre>{@code
+ * TextClassification classification = new TextClassification.Builder()
+ * .setText(classifiedText)
+ * .setEntityType(TextClassifier.TYPE_EMAIL, 0.9)
+ * .setEntityType(TextClassifier.TYPE_OTHER, 0.1)
+ * .setPrimaryAction(intent, label, icon, onClickListener)
+ * .addSecondaryAction(intent1, label1, icon1, onClickListener1)
+ * .addSecondaryAction(intent2, label2, icon2, onClickListener2)
+ * .build();
+ * }</pre>
*/
public static final class Builder {
@NonNull private String mText;
- @NonNull private final List<Drawable> mIcons = new ArrayList<>();
- @NonNull private final List<String> mLabels = new ArrayList<>();
- @NonNull private final List<Intent> mIntents = new ArrayList<>();
- @NonNull private final List<OnClickListener> mOnClickListeners = new ArrayList<>();
- @NonNull private final EntityConfidence<String> mEntityConfidence =
- new EntityConfidence<>();
- private int mLogType;
- @NonNull private String mVersionInfo = "";
+ @NonNull private final List<Drawable> mSecondaryIcons = new ArrayList<>();
+ @NonNull private final List<String> mSecondaryLabels = new ArrayList<>();
+ @NonNull private final List<Intent> mSecondaryIntents = new ArrayList<>();
+ @NonNull private final List<OnClickListener> mSecondaryOnClickListeners = new ArrayList<>();
+ @NonNull private final Map<String, Float> mEntityConfidence = new ArrayMap<>();
+ @Nullable Drawable mPrimaryIcon;
+ @Nullable String mPrimaryLabel;
+ @Nullable Intent mPrimaryIntent;
+ @Nullable OnClickListener mPrimaryOnClickListener;
+ @NonNull private String mSignature = "";
/**
* Sets the classified text.
@@ -325,6 +388,8 @@
/**
* Sets an entity type for the classification result and assigns a confidence score.
+ * If a confidence score had already been set for the specified entity type, this will
+ * override that score.
*
* @param confidenceScore a value from 0 (low confidence) to 1 (high confidence).
* 0 implies the entity does not exist for the classified text.
@@ -333,115 +398,133 @@
public Builder setEntityType(
@NonNull @EntityType String type,
@FloatRange(from = 0.0, to = 1.0) float confidenceScore) {
- mEntityConfidence.setEntityType(type, confidenceScore);
+ mEntityConfidence.put(type, confidenceScore);
return this;
}
/**
- * Adds an action that may be performed on the classified text. The label and icon are used
- * for rendering of widgets that offer the intent. Actions should be added in order of
- * priority and the first one will be treated as the default.
+ * Adds an <i>secondary</i> action that may be performed on the classified text.
+ * Secondary actions are in addition to the <i>primary</i> action which may or may not
+ * exist.
+ *
+ * <p>The label and icon are used for rendering of widgets that offer the intent.
+ * Actions should be added in order of priority.
+ *
+ * <p><stong>Note: </stong> If all input parameters are set to null, this method will be a
+ * no-op.
+ *
+ * @see #setPrimaryAction(Intent, String, Drawable, OnClickListener)
*/
- public Builder addAction(
- Intent intent, @Nullable String label, @Nullable Drawable icon,
+ public Builder addSecondaryAction(
+ @Nullable Intent intent, @Nullable String label, @Nullable Drawable icon,
@Nullable OnClickListener onClickListener) {
- mIntents.add(intent);
- mLabels.add(label);
- mIcons.add(icon);
- mOnClickListeners.add(onClickListener);
+ if (intent != null || label != null || icon != null || onClickListener != null) {
+ mSecondaryIntents.add(intent);
+ mSecondaryLabels.add(label);
+ mSecondaryIcons.add(icon);
+ mSecondaryOnClickListeners.add(onClickListener);
+ }
return this;
}
/**
- * Removes all actions.
+ * Removes all the <i>secondary</i> actions.
*/
- public Builder clearActions() {
- mIntents.clear();
- mOnClickListeners.clear();
- mLabels.clear();
- mIcons.clear();
+ public Builder clearSecondaryActions() {
+ mSecondaryIntents.clear();
+ mSecondaryOnClickListeners.clear();
+ mSecondaryLabels.clear();
+ mSecondaryIcons.clear();
return this;
}
/**
- * Sets the icon for the default action that may be rendered on a widget used to act on the
- * classified text.
+ * Sets the <i>primary</i> action that may be performed on the classified text. This is
+ * equivalent to calling {@code
+ * setIntent(intent).setLabel(label).setIcon(icon).setOnClickListener(onClickListener)}.
+ *
+ * <p><strong>Note: </strong>If all input parameters are null, there will be no
+ * <i>primary</i> action but there may still be <i>secondary</i> actions.
+ *
+ * @see #addSecondaryAction(Intent, String, Drawable, OnClickListener)
+ */
+ public Builder setPrimaryAction(
+ @Nullable Intent intent, @Nullable String label, @Nullable Drawable icon,
+ @Nullable OnClickListener onClickListener) {
+ return setIntent(intent).setLabel(label).setIcon(icon)
+ .setOnClickListener(onClickListener);
+ }
+
+ /**
+ * Sets the icon for the <i>primary</i> action that may be rendered on a widget used to act
+ * on the classified text.
+ *
+ * @see #setPrimaryAction(Intent, String, Drawable, OnClickListener)
*/
public Builder setIcon(@Nullable Drawable icon) {
- ensureDefaultActionAvailable();
- mIcons.set(0, icon);
+ mPrimaryIcon = icon;
return this;
}
/**
- * Sets the label for the default action that may be rendered on a widget used to act on the
- * classified text.
+ * Sets the label for the <i>primary</i> action that may be rendered on a widget used to
+ * act on the classified text.
+ *
+ * @see #setPrimaryAction(Intent, String, Drawable, OnClickListener)
*/
public Builder setLabel(@Nullable String label) {
- ensureDefaultActionAvailable();
- mLabels.set(0, label);
+ mPrimaryLabel = label;
return this;
}
/**
- * Sets the intent for the default action that may be fired to act on the classified text.
+ * Sets the intent for the <i>primary</i> action that may be fired to act on the classified
+ * text.
+ *
+ * @see #setPrimaryAction(Intent, String, Drawable, OnClickListener)
*/
public Builder setIntent(@Nullable Intent intent) {
- ensureDefaultActionAvailable();
- mIntents.set(0, intent);
+ mPrimaryIntent = intent;
return this;
}
/**
- * Sets the MetricsLogger subtype for the action that is performed for this result.
- * @hide
- */
- public Builder setLogType(int type) {
- mLogType = type;
- return this;
- }
-
- /**
- * Sets the OnClickListener for the default action that may be triggered to act on the
- * classified text.
+ * Sets the OnClickListener for the <i>primary</i> action that may be triggered to act on
+ * the classified text.
+ *
+ * @see #setPrimaryAction(Intent, String, Drawable, OnClickListener)
*/
public Builder setOnClickListener(@Nullable OnClickListener onClickListener) {
- ensureDefaultActionAvailable();
- mOnClickListeners.set(0, onClickListener);
+ mPrimaryOnClickListener = onClickListener;
return this;
}
/**
- * Sets information about the classifier model used to generate this TextClassification.
- * @hide
+ * Sets a signature for the TextClassification object.
+ * The TextClassifier that generates the TextClassification object may use it as a way to
+ * internally identify the TextClassification object.
*/
- Builder setVersionInfo(@NonNull String versionInfo) {
- mVersionInfo = Preconditions.checkNotNull(versionInfo);
+ public Builder setSignature(@NonNull String signature) {
+ mSignature = Preconditions.checkNotNull(signature);
return this;
}
/**
- * Ensures that we have at we have storage for the default action.
- */
- private void ensureDefaultActionAvailable() {
- if (mIntents.isEmpty()) mIntents.add(null);
- if (mLabels.isEmpty()) mLabels.add(null);
- if (mIcons.isEmpty()) mIcons.add(null);
- if (mOnClickListeners.isEmpty()) mOnClickListeners.add(null);
- }
-
- /**
* Builds and returns a {@link TextClassification} object.
*/
public TextClassification build() {
return new TextClassification(
- mText, mIcons, mLabels, mIntents, mOnClickListeners, mEntityConfidence,
- mLogType, mVersionInfo);
+ mText,
+ mPrimaryIcon, mPrimaryLabel,
+ mPrimaryIntent, mPrimaryOnClickListener,
+ mSecondaryIcons, mSecondaryLabels,
+ mSecondaryIntents, mSecondaryOnClickListeners,
+ mEntityConfidence, mSignature);
}
}
/**
- * TextClassification optional input parameters.
+ * Optional input parameters for generating TextClassification.
*/
public static final class Options {
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index aeb8489..f4cbc54 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -23,6 +23,8 @@
import android.annotation.WorkerThread;
import android.os.LocaleList;
+import com.android.internal.util.Preconditions;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -35,10 +37,9 @@
public interface TextClassifier {
/** @hide */
- String DEFAULT_LOG_TAG = "TextClassifierImpl";
+ String DEFAULT_LOG_TAG = "androidtc";
- /** @hide */
- String TYPE_UNKNOWN = ""; // TODO: Make this public API.
+ String TYPE_UNKNOWN = "";
String TYPE_OTHER = "other";
String TYPE_EMAIL = "email";
String TYPE_PHONE = "phone";
@@ -70,6 +71,8 @@
*
* @throws IllegalArgumentException if text is null; selectionStartIndex is negative;
* selectionEndIndex is greater than text.length() or not greater than selectionStartIndex
+ *
+ * @see #suggestSelection(CharSequence, int, int)
*/
@WorkerThread
@NonNull
@@ -78,13 +81,46 @@
@IntRange(from = 0) int selectionStartIndex,
@IntRange(from = 0) int selectionEndIndex,
@Nullable TextSelection.Options options) {
+ Utils.validateInput(text, selectionStartIndex, selectionEndIndex);
return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
}
/**
+ * Returns suggested text selection start and end indices, recognized entity types, and their
+ * associated confidence scores. The entity types are ordered from highest to lowest scoring.
+ *
+ * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
+ * {@link #suggestSelection(CharSequence, int, int, TextSelection.Options)}. If that method
+ * calls this method, a stack overflow error will happen.
+ *
+ * @param text text providing context for the selected text (which is specified
+ * by the sub sequence starting at selectionStartIndex and ending at selectionEndIndex)
+ * @param selectionStartIndex start index of the selected part of text
+ * @param selectionEndIndex end index of the selected part of text
+ *
+ * @throws IllegalArgumentException if text is null; selectionStartIndex is negative;
+ * selectionEndIndex is greater than text.length() or not greater than selectionStartIndex
+ *
* @see #suggestSelection(CharSequence, int, int, TextSelection.Options)
*/
- // TODO: Consider deprecating (b/68846316)
+ @WorkerThread
+ @NonNull
+ default TextSelection suggestSelection(
+ @NonNull CharSequence text,
+ @IntRange(from = 0) int selectionStartIndex,
+ @IntRange(from = 0) int selectionEndIndex) {
+ return suggestSelection(text, selectionStartIndex, selectionEndIndex,
+ (TextSelection.Options) null);
+ }
+
+ /**
+ * See {@link #suggestSelection(CharSequence, int, int)} or
+ * {@link #suggestSelection(CharSequence, int, int, TextSelection.Options)}.
+ *
+ * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
+ * {@link #suggestSelection(CharSequence, int, int, TextSelection.Options)}. If that method
+ * calls this method, a stack overflow error will happen.
+ */
@WorkerThread
@NonNull
default TextSelection suggestSelection(
@@ -92,7 +128,10 @@
@IntRange(from = 0) int selectionStartIndex,
@IntRange(from = 0) int selectionEndIndex,
@Nullable LocaleList defaultLocales) {
- return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
+ final TextSelection.Options options = (defaultLocales != null)
+ ? new TextSelection.Options().setDefaultLocales(defaultLocales)
+ : null;
+ return suggestSelection(text, selectionStartIndex, selectionEndIndex, options);
}
/**
@@ -107,6 +146,8 @@
*
* @throws IllegalArgumentException if text is null; startIndex is negative;
* endIndex is greater than text.length() or not greater than startIndex
+ *
+ * @see #classifyText(CharSequence, int, int)
*/
@WorkerThread
@NonNull
@@ -115,13 +156,45 @@
@IntRange(from = 0) int startIndex,
@IntRange(from = 0) int endIndex,
@Nullable TextClassification.Options options) {
+ Utils.validateInput(text, startIndex, endIndex);
return TextClassification.EMPTY;
}
/**
+ * Classifies the specified text and returns a {@link TextClassification} object that can be
+ * used to generate a widget for handling the classified text.
+ *
+ * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
+ * {@link #classifyText(CharSequence, int, int, TextClassification.Options)}. If that method
+ * calls this method, a stack overflow error will happen.
+ *
+ * @param text text providing context for the text to classify (which is specified
+ * by the sub sequence starting at startIndex and ending at endIndex)
+ * @param startIndex start index of the text to classify
+ * @param endIndex end index of the text to classify
+ *
+ * @throws IllegalArgumentException if text is null; startIndex is negative;
+ * endIndex is greater than text.length() or not greater than startIndex
+ *
* @see #classifyText(CharSequence, int, int, TextClassification.Options)
*/
- // TODO: Consider deprecating (b/68846316)
+ @WorkerThread
+ @NonNull
+ default TextClassification classifyText(
+ @NonNull CharSequence text,
+ @IntRange(from = 0) int startIndex,
+ @IntRange(from = 0) int endIndex) {
+ return classifyText(text, startIndex, endIndex, (TextClassification.Options) null);
+ }
+
+ /**
+ * See {@link #classifyText(CharSequence, int, int, TextClassification.Options)} or
+ * {@link #classifyText(CharSequence, int, int)}.
+ *
+ * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
+ * {@link #classifyText(CharSequence, int, int, TextClassification.Options)}. If that method
+ * calls this method, a stack overflow error will happen.
+ */
@WorkerThread
@NonNull
default TextClassification classifyText(
@@ -129,7 +202,10 @@
@IntRange(from = 0) int startIndex,
@IntRange(from = 0) int endIndex,
@Nullable LocaleList defaultLocales) {
- return TextClassification.EMPTY;
+ final TextClassification.Options options = (defaultLocales != null)
+ ? new TextClassification.Options().setDefaultLocales(defaultLocales)
+ : null;
+ return classifyText(text, startIndex, endIndex, options);
}
/**
@@ -137,17 +213,39 @@
* information.
*
* @param text the text to generate annotations for
- * @param options configuration for link generation. If null, defaults will be used.
+ * @param options configuration for link generation
*
* @throws IllegalArgumentException if text is null
+ *
+ * @see #generateLinks(CharSequence)
*/
@WorkerThread
default TextLinks generateLinks(
@NonNull CharSequence text, @Nullable TextLinks.Options options) {
+ Utils.validateInput(text);
return new TextLinks.Builder(text.toString()).build();
}
/**
+ * Returns a {@link TextLinks} that may be applied to the text to annotate it with links
+ * information.
+ *
+ * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
+ * {@link #generateLinks(CharSequence, TextLinks.Options)}. If that method calls this method,
+ * a stack overflow error will happen.
+ *
+ * @param text the text to generate annotations for
+ *
+ * @throws IllegalArgumentException if text is null
+ *
+ * @see #generateLinks(CharSequence, TextLinks.Options)
+ */
+ @WorkerThread
+ default TextLinks generateLinks(@NonNull CharSequence text) {
+ return generateLinks(text, null);
+ }
+
+ /**
* Logs a TextClassifier event.
*
* @param source the text classifier used to generate this event
@@ -164,4 +262,38 @@
default TextClassifierConstants getSettings() {
return TextClassifierConstants.DEFAULT;
}
+
+
+ /**
+ * Utility functions for TextClassifier methods.
+ *
+ * <ul>
+ * <li>Provides validation of input parameters to TextClassifier methods
+ * </ul>
+ *
+ * Intended to be used only in this package.
+ * @hide
+ */
+ final class Utils {
+
+ /**
+ * @throws IllegalArgumentException if text is null; startIndex is negative;
+ * endIndex is greater than text.length() or is not greater than startIndex;
+ * options is null
+ */
+ static void validateInput(
+ @NonNull CharSequence text, int startIndex, int endIndex) {
+ Preconditions.checkArgument(text != null);
+ Preconditions.checkArgument(startIndex >= 0);
+ Preconditions.checkArgument(endIndex <= text.length());
+ Preconditions.checkArgument(endIndex > startIndex);
+ }
+
+ /**
+ * @throws IllegalArgumentException if text is null or options is null
+ */
+ static void validateInput(@NonNull CharSequence text) {
+ Preconditions.checkArgument(text != null);
+ }
+ }
}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 2ad6e02..6cf6b69 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -32,7 +32,7 @@
import android.provider.Settings;
import android.text.util.Linkify;
import android.util.Patterns;
-import android.widget.TextViewMetrics;
+import android.view.View.OnClickListener;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
@@ -90,8 +90,8 @@
@Override
public TextSelection suggestSelection(
@NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex,
- @Nullable TextSelection.Options options) {
- validateInput(text, selectionStartIndex, selectionEndIndex);
+ @NonNull TextSelection.Options options) {
+ Utils.validateInput(text, selectionStartIndex, selectionEndIndex);
try {
if (text.length() > 0) {
final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
@@ -121,8 +121,8 @@
tsBuilder.setEntityType(results[i].mCollection, results[i].mScore);
}
return tsBuilder
- .setLogSource(LOG_TAG)
- .setVersionInfo(getVersionInfo())
+ .setSignature(
+ getSignature(string, selectionStartIndex, selectionEndIndex))
.build();
} else {
// We can not trust the result. Log the issue and ignore the result.
@@ -141,18 +141,10 @@
}
@Override
- public TextSelection suggestSelection(
- @NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex,
- @Nullable LocaleList defaultLocales) {
- return suggestSelection(text, selectionStartIndex, selectionEndIndex,
- new TextSelection.Options().setDefaultLocales(defaultLocales));
- }
-
- @Override
public TextClassification classifyText(
@NonNull CharSequence text, int startIndex, int endIndex,
- @Nullable TextClassification.Options options) {
- validateInput(text, startIndex, endIndex);
+ @NonNull TextClassification.Options options) {
+ Utils.validateInput(text, startIndex, endIndex);
try {
if (text.length() > 0) {
final String string = text.toString();
@@ -162,8 +154,7 @@
getHintFlags(string, startIndex, endIndex));
if (results.length > 0) {
final TextClassification classificationResult =
- createClassificationResult(
- results, string.subSequence(startIndex, endIndex));
+ createClassificationResult(results, string, startIndex, endIndex);
return classificationResult;
}
}
@@ -176,17 +167,9 @@
}
@Override
- public TextClassification classifyText(
- @NonNull CharSequence text, int startIndex, int endIndex,
- @Nullable LocaleList defaultLocales) {
- return classifyText(text, startIndex, endIndex,
- new TextClassification.Options().setDefaultLocales(defaultLocales));
- }
-
- @Override
public TextLinks generateLinks(
- @NonNull CharSequence text, @Nullable TextLinks.Options options) {
- Preconditions.checkNotNull(text);
+ @NonNull CharSequence text, @NonNull TextLinks.Options options) {
+ Utils.validateInput(text);
final String textString = text.toString();
final TextLinks.Builder builder = new TextLinks.Builder(textString);
try {
@@ -245,13 +228,13 @@
}
}
- @NonNull
- private String getVersionInfo() {
+ private String getSignature(String text, int start, int end) {
synchronized (mSmartSelectionLock) {
- if (mLocale != null) {
- return String.format("%s_v%d", mLocale.toLanguageTag(), mVersion);
- }
- return "";
+ final String versionInfo = (mLocale != null)
+ ? String.format(Locale.US, "%s_v%d", mLocale.toLanguageTag(), mVersion)
+ : "";
+ final int hash = Objects.hash(text, start, end, mContext.getPackageName());
+ return String.format(Locale.US, "%s|%s|%d", LOG_TAG, versionInfo, hash);
}
}
@@ -387,9 +370,11 @@
}
private TextClassification createClassificationResult(
- SmartSelection.ClassificationResult[] classifications, CharSequence text) {
+ SmartSelection.ClassificationResult[] classifications,
+ String text, int start, int end) {
+ final String classifiedText = text.substring(start, end);
final TextClassification.Builder builder = new TextClassification.Builder()
- .setText(text.toString());
+ .setText(classifiedText);
final int size = classifications.length;
for (int i = 0; i < size; i++) {
@@ -397,50 +382,54 @@
}
final String type = getHighestScoringType(classifications);
- builder.setLogType(IntentFactory.getLogType(type));
+ addActions(builder, IntentFactory.create(mContext, type, text));
- final List<Intent> intents = IntentFactory.create(mContext, type, text.toString());
- for (Intent intent : intents) {
- extendClassificationWithIntent(intent, builder);
- }
-
- return builder.setVersionInfo(getVersionInfo()).build();
+ return builder.setSignature(getSignature(text, start, end)).build();
}
- /** Extends the classification with the intent if it can be resolved. */
- private void extendClassificationWithIntent(Intent intent, TextClassification.Builder builder) {
- final PackageManager pm;
- final ResolveInfo resolveInfo;
- if (intent != null) {
- pm = mContext.getPackageManager();
- resolveInfo = pm.resolveActivity(intent, 0);
- } else {
- pm = null;
- resolveInfo = null;
- }
- if (resolveInfo != null && resolveInfo.activityInfo != null) {
- final String packageName = resolveInfo.activityInfo.packageName;
- CharSequence label;
- Drawable icon;
- if ("android".equals(packageName)) {
- // Requires the chooser to find an activity to handle the intent.
- label = IntentFactory.getLabel(mContext, intent);
- icon = null;
+ /** Extends the classification with the intents that can be resolved. */
+ private void addActions(
+ TextClassification.Builder builder, List<Intent> intents) {
+ final PackageManager pm = mContext.getPackageManager();
+ final int size = intents.size();
+ for (int i = 0; i < size; i++) {
+ final Intent intent = intents.get(i);
+ final ResolveInfo resolveInfo;
+ if (intent != null) {
+ resolveInfo = pm.resolveActivity(intent, 0);
} else {
- // A default activity will handle the intent.
- intent.setComponent(new ComponentName(packageName, resolveInfo.activityInfo.name));
- icon = resolveInfo.activityInfo.loadIcon(pm);
- if (icon == null) {
- icon = resolveInfo.loadIcon(pm);
+ resolveInfo = null;
+ }
+ if (resolveInfo != null && resolveInfo.activityInfo != null) {
+ final String packageName = resolveInfo.activityInfo.packageName;
+ CharSequence label;
+ Drawable icon;
+ if ("android".equals(packageName)) {
+ // Requires the chooser to find an activity to handle the intent.
+ label = IntentFactory.getLabel(mContext, intent);
+ icon = null;
+ } else {
+ // A default activity will handle the intent.
+ intent.setComponent(
+ new ComponentName(packageName, resolveInfo.activityInfo.name));
+ icon = resolveInfo.activityInfo.loadIcon(pm);
+ if (icon == null) {
+ icon = resolveInfo.loadIcon(pm);
+ }
+ label = resolveInfo.activityInfo.loadLabel(pm);
+ if (label == null) {
+ label = resolveInfo.loadLabel(pm);
+ }
}
- label = resolveInfo.activityInfo.loadLabel(pm);
- if (label == null) {
- label = resolveInfo.loadLabel(pm);
+ final String labelString = (label != null) ? label.toString() : null;
+ final OnClickListener onClickListener =
+ TextClassification.createStartActivityOnClickListener(mContext, intent);
+ if (i == 0) {
+ builder.setPrimaryAction(intent, labelString, icon, onClickListener);
+ } else {
+ builder.addSecondaryAction(intent, labelString, icon, onClickListener);
}
}
- builder.addAction(
- intent, label != null ? label.toString() : null, icon,
- TextClassification.createStartActivityOnClickListener(mContext, intent));
}
}
@@ -486,17 +475,6 @@
}
/**
- * @throws IllegalArgumentException if text is null; startIndex is negative;
- * endIndex is greater than text.length() or is not greater than startIndex
- */
- private static void validateInput(@NonNull CharSequence text, int startIndex, int endIndex) {
- Preconditions.checkArgument(text != null);
- Preconditions.checkArgument(startIndex >= 0);
- Preconditions.checkArgument(endIndex <= text.length());
- Preconditions.checkArgument(endIndex > startIndex);
- }
-
- /**
* Creates intents based on the classification type.
*/
private static final class IntentFactory {
@@ -584,22 +562,5 @@
return null;
}
}
-
- @Nullable
- public static int getLogType(String type) {
- type = type.trim().toLowerCase(Locale.ENGLISH);
- switch (type) {
- case TextClassifier.TYPE_EMAIL:
- return TextViewMetrics.SUBTYPE_ASSIST_MENU_ITEM_EMAIL;
- case TextClassifier.TYPE_PHONE:
- return TextViewMetrics.SUBTYPE_ASSIST_MENU_ITEM_PHONE;
- case TextClassifier.TYPE_ADDRESS:
- return TextViewMetrics.SUBTYPE_ASSIST_MENU_ITEM_ADDRESS;
- case TextClassifier.TYPE_URL:
- return TextViewMetrics.SUBTYPE_ASSIST_MENU_ITEM_URL;
- default:
- return TextViewMetrics.SUBTYPE_ASSIST_MENU_ITEM_OTHER;
- }
- }
}
}
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
index f3cc827..0e039e3 100644
--- a/core/java/android/view/textclassifier/TextLinks.java
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -103,11 +103,7 @@
mOriginalText = originalText;
mStart = start;
mEnd = end;
- mEntityScores = new EntityConfidence<>();
-
- for (Map.Entry<String, Float> entry : entityScores.entrySet()) {
- mEntityScores.setEntityType(entry.getKey(), entry.getValue());
- }
+ mEntityScores = new EntityConfidence<>(entityScores);
}
/**
@@ -161,39 +157,28 @@
* Optional input parameters for generating TextLinks.
*/
public static final class Options {
- private final LocaleList mLocaleList;
- private Options(LocaleList localeList) {
- this.mLocaleList = localeList;
+ private LocaleList mDefaultLocales;
+
+ /**
+ * @param defaultLocales ordered list of locale preferences that may be used to disambiguate
+ * the provided text. If no locale preferences exist, set this to null or an empty
+ * locale list.
+ */
+ public Options setDefaultLocales(@Nullable LocaleList defaultLocales) {
+ mDefaultLocales = defaultLocales;
+ return this;
}
/**
- * Builder to construct Options.
+ * @return ordered list of locale preferences that can be used to disambiguate
+ * the provided text.
*/
- public static final class Builder {
- private LocaleList mLocaleList;
-
- /**
- * Sets the LocaleList to use.
- *
- * @return this Builder.
- */
- public Builder setLocaleList(@Nullable LocaleList localeList) {
- this.mLocaleList = localeList;
- return this;
- }
-
- /**
- * Builds the Options object.
- */
- public Options build() {
- return new Options(mLocaleList);
- }
+ @Nullable
+ public LocaleList getDefaultLocales() {
+ return mDefaultLocales;
}
- public @Nullable LocaleList getDefaultLocales() {
- return mLocaleList;
- }
- };
+ }
/**
* A function to create spans from TextLinks.
@@ -204,13 +189,10 @@
* @hide
*/
public static final Function<TextLink, ClickableSpan> DEFAULT_SPAN_FACTORY =
- new Function<TextLink, ClickableSpan>() {
- @Override
- public ClickableSpan apply(TextLink textLink) {
- // TODO: Implement.
- throw new UnsupportedOperationException("Not yet implemented");
- }
- };
+ textLink -> {
+ // TODO: Implement.
+ throw new UnsupportedOperationException("Not yet implemented");
+ };
/**
* A builder to construct a TextLinks instance.
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index 0a67954..25e9e7e 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -21,11 +21,13 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.LocaleList;
+import android.util.ArrayMap;
import android.view.textclassifier.TextClassifier.EntityType;
import com.android.internal.util.Preconditions;
-import java.util.List;
+import java.util.Locale;
+import java.util.Map;
/**
* Information about where text selection should be.
@@ -35,19 +37,15 @@
private final int mStartIndex;
private final int mEndIndex;
@NonNull private final EntityConfidence<String> mEntityConfidence;
- @NonNull private final List<String> mEntities;
- @NonNull private final String mLogSource;
- @NonNull private final String mVersionInfo;
+ @NonNull private final String mSignature;
private TextSelection(
- int startIndex, int endIndex, @NonNull EntityConfidence<String> entityConfidence,
- @NonNull String logSource, @NonNull String versionInfo) {
+ int startIndex, int endIndex, @NonNull Map<String, Float> entityConfidence,
+ @NonNull String signature) {
mStartIndex = startIndex;
mEndIndex = endIndex;
mEntityConfidence = new EntityConfidence<>(entityConfidence);
- mEntities = mEntityConfidence.getEntities();
- mLogSource = logSource;
- mVersionInfo = versionInfo;
+ mSignature = signature;
}
/**
@@ -69,7 +67,7 @@
*/
@IntRange(from = 0)
public int getEntityCount() {
- return mEntities.size();
+ return mEntityConfidence.getEntities().size();
}
/**
@@ -81,7 +79,7 @@
*/
@NonNull
public @EntityType String getEntity(int index) {
- return mEntities.get(index);
+ return mEntityConfidence.getEntities().get(index);
}
/**
@@ -95,27 +93,21 @@
}
/**
- * Returns a tag for the source classifier used to generate this result.
- * @hide
+ * Returns the signature for this object.
+ * The TextClassifier that generates this object may use it as a way to internally identify
+ * this object.
*/
@NonNull
- public String getSourceClassifier() {
- return mLogSource;
- }
-
- /**
- * Returns information about the classifier model used to generate this TextSelection.
- * @hide
- */
- @NonNull
- public String getVersionInfo() {
- return mVersionInfo;
+ public String getSignature() {
+ return mSignature;
}
@Override
public String toString() {
- return String.format("TextSelection {%d, %d, %s}",
- mStartIndex, mEndIndex, mEntityConfidence);
+ return String.format(
+ Locale.US,
+ "TextSelection {startIndex=%d, endIndex=%d, entities=%s, signature=%s}",
+ mStartIndex, mEndIndex, mEntityConfidence, mSignature);
}
/**
@@ -125,10 +117,8 @@
private final int mStartIndex;
private final int mEndIndex;
- @NonNull private final EntityConfidence<String> mEntityConfidence =
- new EntityConfidence<>();
- @NonNull private String mLogSource = "";
- @NonNull private String mVersionInfo = "";
+ @NonNull private final Map<String, Float> mEntityConfidence = new ArrayMap<>();
+ @NonNull private String mSignature = "";
/**
* Creates a builder used to build {@link TextSelection} objects.
@@ -153,25 +143,18 @@
public Builder setEntityType(
@NonNull @EntityType String type,
@FloatRange(from = 0.0, to = 1.0) float confidenceScore) {
- mEntityConfidence.setEntityType(type, confidenceScore);
+ mEntityConfidence.put(type, confidenceScore);
return this;
}
/**
- * Sets a tag for the source classifier used to generate this result.
- * @hide
+ * Sets a signature for the TextSelection object.
+ *
+ * The TextClassifier that generates the TextSelection object may use it as a way to
+ * internally identify the TextSelection object.
*/
- Builder setLogSource(@NonNull String logSource) {
- mLogSource = Preconditions.checkNotNull(logSource);
- return this;
- }
-
- /**
- * Sets information about the classifier model used to generate this TextSelection.
- * @hide
- */
- Builder setVersionInfo(@NonNull String versionInfo) {
- mVersionInfo = Preconditions.checkNotNull(versionInfo);
+ public Builder setSignature(@NonNull String signature) {
+ mSignature = Preconditions.checkNotNull(signature);
return this;
}
@@ -180,12 +163,12 @@
*/
public TextSelection build() {
return new TextSelection(
- mStartIndex, mEndIndex, mEntityConfidence, mLogSource, mVersionInfo);
+ mStartIndex, mEndIndex, mEntityConfidence, mSignature);
}
}
/**
- * TextSelection optional input parameters.
+ * Optional input parameters for generating TextSelection.
*/
public static final class Options {
diff --git a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
index 2833564..157b3d8 100644
--- a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
+++ b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
@@ -473,7 +473,7 @@
final String entityType = classification.getEntityCount() > 0
? classification.getEntity(0)
: TextClassifier.TYPE_UNKNOWN;
- final String versionTag = classification.getVersionInfo();
+ final String versionTag = getVersionInfo(classification.getSignature());
return new SelectionEvent(
start, end, EventType.SELECTION_MODIFIED, entityType, versionTag);
}
@@ -489,7 +489,7 @@
*/
public static SelectionEvent selectionModified(
int start, int end, @NonNull TextSelection selection) {
- final boolean smartSelection = selection.getSourceClassifier()
+ final boolean smartSelection = getSourceClassifier(selection.getSignature())
.equals(TextClassifier.DEFAULT_LOG_TAG);
final int eventType;
if (smartSelection) {
@@ -503,7 +503,7 @@
final String entityType = selection.getEntityCount() > 0
? selection.getEntity(0)
: TextClassifier.TYPE_UNKNOWN;
- final String versionTag = selection.getVersionInfo();
+ final String versionTag = getVersionInfo(selection.getSignature());
return new SelectionEvent(start, end, eventType, entityType, versionTag);
}
@@ -538,26 +538,25 @@
final String entityType = classification.getEntityCount() > 0
? classification.getEntity(0)
: TextClassifier.TYPE_UNKNOWN;
- final String versionTag = classification.getVersionInfo();
+ final String versionTag = getVersionInfo(classification.getSignature());
return new SelectionEvent(start, end, actionType, entityType, versionTag);
}
- private boolean isActionType() {
- switch (mEventType) {
- case ActionType.OVERTYPE: // fall through
- case ActionType.COPY: // fall through
- case ActionType.PASTE: // fall through
- case ActionType.CUT: // fall through
- case ActionType.SHARE: // fall through
- case ActionType.SMART_SHARE: // fall through
- case ActionType.DRAG: // fall through
- case ActionType.ABANDON: // fall through
- case ActionType.SELECT_ALL: // fall through
- case ActionType.RESET: // fall through
- return true;
- default:
- return false;
+ private static String getVersionInfo(String signature) {
+ final int start = signature.indexOf("|");
+ final int end = signature.indexOf("|", start);
+ if (start >= 0 && end >= start) {
+ return signature.substring(start, end);
}
+ return "";
+ }
+
+ private static String getSourceClassifier(String signature) {
+ final int end = signature.indexOf("|");
+ if (end >= 0) {
+ return signature.substring(0, end);
+ }
+ return "";
}
private boolean isTerminal() {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 665d694..6f99254 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2758,7 +2758,9 @@
* <p>For example, an HTML form with 2 fields for username and password:
*
* <pre class="prettyprint">
+ * <label>Username:</label>
* <input type="text" name="username" id="user" value="Type your username" autocomplete="username" placeholder="Email or username">
+ * <label>Password:</label>
* <input type="password" name="password" id="pass" autocomplete="current-password" placeholder="Password">
* </pre>
*
@@ -2772,6 +2774,7 @@
* username.setHtmlInfo(username.newHtmlInfoBuilder("input")
* .addAttribute("type", "text")
* .addAttribute("name", "username")
+ * .addAttribute("label", "Username:")
* .build());
* username.setHint("Email or username");
* username.setAutofillType(View.AUTOFILL_TYPE_TEXT);
@@ -2785,6 +2788,7 @@
* password.setHtmlInfo(password.newHtmlInfoBuilder("input")
* .addAttribute("type", "password")
* .addAttribute("name", "password")
+ * .addAttribute("label", "Password:")
* .build());
* password.setHint("Password");
* password.setAutofillType(View.AUTOFILL_TYPE_TEXT);
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 517ad07..46c3983 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -364,13 +364,13 @@
}
/**
- * Notify the host application to handle a SSL client certificate
- * request. The host application is responsible for showing the UI
- * if desired and providing the keys. There are three ways to
- * respond: proceed(), cancel() or ignore(). Webview stores the response
- * in memory (for the life of the application) if proceed() or cancel() is
- * called and does not call {@code onReceivedClientCertRequest()} again for the
- * same host and port pair. Webview does not store the response if ignore()
+ * Notify the host application to handle a SSL client certificate request. The host application
+ * is responsible for showing the UI if desired and providing the keys. There are three ways to
+ * respond: {@link ClientCertRequest#proceed}, {@link ClientCertRequest#cancel}, or {@link
+ * ClientCertRequest#ignore}. Webview stores the response in memory (for the life of the
+ * application) if {@link ClientCertRequest#proceed} or {@link ClientCertRequest#cancel} is
+ * called and does not call {@code onReceivedClientCertRequest()} again for the same host and
+ * port pair. Webview does not store the response if {@link ClientCertRequest#ignore}
* is called. Note that, multiple layers in chromium network stack might be
* caching the responses, so the behavior for ignore is only a best case
* effort.
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 797bdfb..9db0e8d 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -265,10 +265,10 @@
+ "packageName mismatch, expected: "
+ chosen.packageName + " actual: " + toUse.packageName);
}
- if (chosen.versionCode > toUse.versionCode) {
+ if (chosen.getLongVersionCode() > toUse.getLongVersionCode()) {
throw new MissingWebViewPackageException("Failed to verify WebView provider, "
- + "version code is lower than expected: " + chosen.versionCode
- + " actual: " + toUse.versionCode);
+ + "version code is lower than expected: " + chosen.getLongVersionCode()
+ + " actual: " + toUse.getLongVersionCode());
}
if (getWebViewLibrary(toUse.applicationInfo) == null) {
throw new MissingWebViewPackageException("Tried to load an invalid WebView provider: "
@@ -401,7 +401,7 @@
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " +
- sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
+ sPackageInfo.versionName + " (code " + sPackageInfo.getLongVersionCode() + ")");
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
try {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 05cba1e..df97112 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -41,7 +41,6 @@
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.metrics.LogMaker;
import android.os.Bundle;
import android.os.LocaleList;
import android.os.Parcel;
@@ -3982,31 +3981,39 @@
}
final TextClassification textClassification =
getSelectionActionModeHelper().getTextClassification();
- final int count = textClassification != null ? textClassification.getActionCount() : 0;
+ if (textClassification == null) {
+ return;
+ }
+ if (isValidAssistMenuItem(
+ textClassification.getIcon(),
+ textClassification.getLabel(),
+ textClassification.getOnClickListener(),
+ textClassification.getIntent())) {
+ final MenuItem item = menu.add(
+ TextView.ID_ASSIST, TextView.ID_ASSIST, MENU_ITEM_ORDER_ASSIST,
+ textClassification.getLabel())
+ .setIcon(textClassification.getIcon())
+ .setIntent(textClassification.getIntent());
+ item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ mAssistClickHandlers.put(item, textClassification.getOnClickListener());
+ }
+ final int count = textClassification.getSecondaryActionsCount();
for (int i = 0; i < count; i++) {
- if (!isValidAssistMenuItem(i)) {
+ if (!isValidAssistMenuItem(
+ textClassification.getSecondaryIcon(i),
+ textClassification.getSecondaryLabel(i),
+ textClassification.getSecondaryOnClickListener(i),
+ textClassification.getSecondaryIntent(i))) {
continue;
}
- final int groupId = TextView.ID_ASSIST;
- final int order = (i == 0)
- ? MENU_ITEM_ORDER_ASSIST
- : MENU_ITEM_ORDER_SECONDARY_ASSIST_ACTIONS_START + i;
- final int id = (i == 0) ? TextView.ID_ASSIST : Menu.NONE;
- final int showAsFlag = (i == 0)
- ? MenuItem.SHOW_AS_ACTION_ALWAYS
- : MenuItem.SHOW_AS_ACTION_NEVER;
+ final int order = MENU_ITEM_ORDER_SECONDARY_ASSIST_ACTIONS_START + i;
final MenuItem item = menu.add(
- groupId, id, order, textClassification.getLabel(i))
- .setIcon(textClassification.getIcon(i))
- .setIntent(textClassification.getIntent(i));
- item.setShowAsAction(showAsFlag);
- mAssistClickHandlers.put(item, textClassification.getOnClickListener(i));
- if (id == TextView.ID_ASSIST) {
- mMetricsLogger.write(
- new LogMaker(MetricsEvent.TEXT_SELECTION_MENU_ITEM_ASSIST)
- .setType(MetricsEvent.TYPE_OPEN)
- .setSubtype(textClassification.getLogType()));
- }
+ TextView.ID_ASSIST, Menu.NONE, order,
+ textClassification.getSecondaryLabel(i))
+ .setIcon(textClassification.getSecondaryIcon(i))
+ .setIntent(textClassification.getSecondaryIntent(i));
+ item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+ mAssistClickHandlers.put(item, textClassification.getSecondaryOnClickListener(i));
}
}
@@ -4022,18 +4029,9 @@
}
}
- private boolean isValidAssistMenuItem(int index) {
- final TextClassification textClassification =
- getSelectionActionModeHelper().getTextClassification();
- if (!mTextView.isDeviceProvisioned() || textClassification == null
- || index < 0 || index >= textClassification.getActionCount()) {
- return false;
- }
- final Drawable icon = textClassification.getIcon(index);
- final CharSequence label = textClassification.getLabel(index);
+ private boolean isValidAssistMenuItem(
+ Drawable icon, CharSequence label, OnClickListener onClick, Intent intent) {
final boolean hasUi = icon != null || !TextUtils.isEmpty(label);
- final OnClickListener onClick = textClassification.getOnClickListener(index);
- final Intent intent = textClassification.getIntent(index);
final boolean hasAction = onClick != null || isSupportedIntent(intent);
return hasUi && hasAction;
}
@@ -4079,11 +4077,6 @@
if (onClickListener != null) {
onClickListener.onClick(mTextView);
stopTextActionMode();
- if (assistMenuItem.getItemId() == TextView.ID_ASSIST) {
- mMetricsLogger.action(
- MetricsEvent.ACTION_TEXT_SELECTION_MENU_ITEM_ASSIST,
- textClassification.getLogType());
- }
}
// We tried our best.
return true;
@@ -6594,7 +6587,7 @@
Editor.MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START + i,
getLabel(resolveInfo))
.setIntent(createProcessTextIntentForResolveInfo(resolveInfo))
- .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
}
}
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index 1279040..7156300 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -570,11 +570,12 @@
mFormatChangeObserver = new FormatChangeObserver(getHandler());
}
final ContentResolver resolver = getContext().getContentResolver();
+ Uri uri = Settings.System.getUriFor(Settings.System.TIME_12_24);
if (mShowCurrentUserTime) {
- resolver.registerContentObserver(Settings.System.CONTENT_URI, true,
+ resolver.registerContentObserver(uri, true,
mFormatChangeObserver, UserHandle.USER_ALL);
} else {
- resolver.registerContentObserver(Settings.System.CONTENT_URI, true,
+ resolver.registerContentObserver(uri, true,
mFormatChangeObserver);
}
}
diff --git a/core/java/android/widget/TextViewMetrics.java b/core/java/android/widget/TextViewMetrics.java
index 96d1794..738a574 100644
--- a/core/java/android/widget/TextViewMetrics.java
+++ b/core/java/android/widget/TextViewMetrics.java
@@ -37,29 +37,4 @@
* Long press on TextView - drag and drop started.
*/
public static final int SUBTYPE_LONG_PRESS_DRAG_AND_DROP = 2;
-
- /**
- * Assist menu item (shown or clicked) - classification: other.
- */
- public static final int SUBTYPE_ASSIST_MENU_ITEM_OTHER = 0;
-
- /**
- * Assist menu item (shown or clicked) - classification: email.
- */
- public static final int SUBTYPE_ASSIST_MENU_ITEM_EMAIL = 1;
-
- /**
- * Assist menu item (shown or clicked) - classification: phone.
- */
- public static final int SUBTYPE_ASSIST_MENU_ITEM_PHONE = 2;
-
- /**
- * Assist menu item (shown or clicked) - classification: address.
- */
- public static final int SUBTYPE_ASSIST_MENU_ITEM_ADDRESS = 3;
-
- /**
- * Assist menu item (shown or clicked) - classification: url.
- */
- public static final int SUBTYPE_ASSIST_MENU_ITEM_URL = 4;
}
diff --git a/services/core/java/com/android/server/policy/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
similarity index 62%
rename from services/core/java/com/android/server/policy/AccessibilityShortcutController.java
rename to core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index 55c582e..293471c 100644
--- a/services/core/java/com/android/server/policy/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Google Inc.
+ * Copyright 2017 Google Inc.
*
* 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
@@ -14,7 +14,7 @@
* the License.
*/
-package com.android.server.policy;
+package com.android.internal.accessibility;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.ActivityManager;
@@ -35,6 +35,7 @@
import android.os.Vibrator;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.Slog;
import android.view.Window;
import android.view.WindowManager;
@@ -43,20 +44,30 @@
import android.widget.Toast;
import com.android.internal.R;
-import java.util.List;
+import java.util.Collections;
+import java.util.Map;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
+import static com.android.internal.util.ArrayUtils.convertToLongArray;
+
/**
* Class to help manage the accessibility shortcut
*/
public class AccessibilityShortcutController {
private static final String TAG = "AccessibilityShortcutController";
+
+ // Dummy component names for framework features
+ public static final ComponentName COLOR_INVERSION_COMPONENT_NAME =
+ new ComponentName("com.android.server.accessibility", "ColorInversion");
+ public static final ComponentName DALTONIZER_COMPONENT_NAME =
+ new ComponentName("com.android.server.accessibility", "Daltonizer");
+
private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY)
.build();
-
+ private static Map<ComponentName, ToggleableFrameworkFeatureInfo> sFrameworkShortcutFeaturesMap;
private final Context mContext;
private AlertDialog mAlertDialog;
@@ -67,6 +78,15 @@
// Visible for testing
public FrameworkObjectProvider mFrameworkObjectProvider = new FrameworkObjectProvider();
+ /**
+ * Get the component name string for the service or feature currently assigned to the
+ * accessiblity shortcut
+ *
+ * @param context A valid context
+ * @param userId The user ID of interest
+ * @return The flattened component name string of the service selected by the user, or the
+ * string for the default service if the user has not made a selection
+ */
public static String getTargetServiceComponentNameString(
Context context, int userId) {
final String currentShortcutServiceId = Settings.Secure.getStringForUser(
@@ -78,6 +98,29 @@
return context.getString(R.string.config_defaultAccessibilityService);
}
+ /**
+ * @return An immutable map from dummy component names to feature info for toggling a framework
+ * feature
+ */
+ public static Map<ComponentName, ToggleableFrameworkFeatureInfo>
+ getFrameworkShortcutFeaturesMap() {
+ if (sFrameworkShortcutFeaturesMap == null) {
+ Map<ComponentName, ToggleableFrameworkFeatureInfo> featuresMap = new ArrayMap<>(2);
+ featuresMap.put(COLOR_INVERSION_COMPONENT_NAME,
+ new ToggleableFrameworkFeatureInfo(
+ Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
+ "1" /* Value to enable */, "0" /* Value to disable */,
+ R.string.color_inversion_feature_name));
+ featuresMap.put(DALTONIZER_COMPONENT_NAME,
+ new ToggleableFrameworkFeatureInfo(
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
+ "1" /* Value to enable */, "0" /* Value to disable */,
+ R.string.color_correction_feature_name));
+ sFrameworkShortcutFeaturesMap = Collections.unmodifiableMap(featuresMap);
+ }
+ return sFrameworkShortcutFeaturesMap;
+ }
+
public AccessibilityShortcutController(Context context, Handler handler, int initialUserId) {
mContext = context;
mUserId = initialUserId;
@@ -160,8 +203,8 @@
if ((vibrator != null) && vibrator.hasVibrator()) {
// Don't check if haptics are disabled, as we need to alert the user that their
// way of interacting with the phone may change if they activate the shortcut
- long[] vibePattern = PhoneWindowManager.getLongIntArray(mContext.getResources(),
- R.array.config_longPressVibePattern);
+ long[] vibePattern = convertToLongArray(
+ mContext.getResources().getIntArray(R.array.config_longPressVibePattern));
vibrator.vibrate(vibePattern, -1, VIBRATION_ATTRIBUTES);
}
@@ -187,22 +230,24 @@
}
// Show a toast alerting the user to what's happening
- final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
- if (serviceInfo == null) {
+ final String serviceName = getShortcutFeatureDescription(false /* no summary */);
+ if (serviceName == null) {
Slog.e(TAG, "Accessibility shortcut set to invalid service");
return;
}
- String toastMessageFormatString = mContext.getString(isServiceEnabled(serviceInfo)
- ? R.string.accessibility_shortcut_disabling_service
- : R.string.accessibility_shortcut_enabling_service);
- String toastMessage = String.format(toastMessageFormatString,
- serviceInfo.getResolveInfo()
- .loadLabel(mContext.getPackageManager()).toString());
- Toast warningToast = mFrameworkObjectProvider.makeToastFromText(
- mContext, toastMessage, Toast.LENGTH_LONG);
- warningToast.getWindowParams().privateFlags |=
- WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
- warningToast.show();
+ // For accessibility services, show a toast explaining what we're doing.
+ final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
+ if (serviceInfo != null) {
+ String toastMessageFormatString = mContext.getString(isServiceEnabled(serviceInfo)
+ ? R.string.accessibility_shortcut_disabling_service
+ : R.string.accessibility_shortcut_enabling_service);
+ String toastMessage = String.format(toastMessageFormatString, serviceName);
+ Toast warningToast = mFrameworkObjectProvider.makeToastFromText(
+ mContext, toastMessage, Toast.LENGTH_LONG);
+ warningToast.getWindowParams().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ warningToast.show();
+ }
mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext)
.performAccessibilityShortcut();
@@ -210,18 +255,18 @@
}
private AlertDialog createShortcutWarningDialog(int userId) {
- final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
+ final String serviceDescription = getShortcutFeatureDescription(true /* Include summary */);
- if (serviceInfo == null) {
+ if (serviceDescription == null) {
return null;
}
final String warningMessage = String.format(
mContext.getString(R.string.accessibility_shortcut_toogle_warning),
- serviceInfo.getResolveInfo().loadLabel(mContext.getPackageManager()).toString());
+ serviceDescription);
final AlertDialog alertDialog = mFrameworkObjectProvider.getAlertDialogBuilder(
// Use SystemUI context so we pick up any theme set in a vendor overlay
- ActivityThread.currentActivityThread().getSystemUiContext())
+ mFrameworkObjectProvider.getSystemUiContext())
.setTitle(R.string.accessibility_shortcut_warning_dialog_title)
.setMessage(warningMessage)
.setCancelable(false)
@@ -253,6 +298,34 @@
ComponentName.unflattenFromString(currentShortcutServiceString));
}
+ private String getShortcutFeatureDescription(boolean includeSummary) {
+ final String currentShortcutServiceString = getTargetServiceComponentNameString(
+ mContext, UserHandle.USER_CURRENT);
+ if (currentShortcutServiceString == null) {
+ return null;
+ }
+ final ComponentName targetComponentName =
+ ComponentName.unflattenFromString(currentShortcutServiceString);
+ final ToggleableFrameworkFeatureInfo frameworkFeatureInfo =
+ getFrameworkShortcutFeaturesMap().get(targetComponentName);
+ if (frameworkFeatureInfo != null) {
+ return frameworkFeatureInfo.getLabel(mContext);
+ }
+ final AccessibilityServiceInfo serviceInfo = mFrameworkObjectProvider
+ .getAccessibilityManagerInstance(mContext).getInstalledServiceInfoWithComponentName(
+ targetComponentName);
+ if (serviceInfo == null) {
+ return null;
+ }
+ final PackageManager pm = mContext.getPackageManager();
+ String label = serviceInfo.getResolveInfo().loadLabel(pm).toString();
+ String summary = serviceInfo.loadSummary(pm).toString();
+ if (!includeSummary || TextUtils.isEmpty(summary)) {
+ return label;
+ }
+ return String.format("%s\n%s", label, summary);
+ }
+
private boolean isServiceEnabled(AccessibilityServiceInfo serviceInfo) {
AccessibilityManager accessibilityManager =
mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext);
@@ -264,6 +337,51 @@
return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
}
+ /**
+ * Immutable class to hold info about framework features that can be controlled by shortcut
+ */
+ public static class ToggleableFrameworkFeatureInfo {
+ private final String mSettingKey;
+ private final String mSettingOnValue;
+ private final String mSettingOffValue;
+ private final int mLabelStringResourceId;
+ // These go to the settings wrapper
+ private int mIconDrawableId;
+
+ ToggleableFrameworkFeatureInfo(String settingKey, String settingOnValue,
+ String settingOffValue, int labelStringResourceId) {
+ mSettingKey = settingKey;
+ mSettingOnValue = settingOnValue;
+ mSettingOffValue = settingOffValue;
+ mLabelStringResourceId = labelStringResourceId;
+ }
+
+ /**
+ * @return The settings key to toggle between two values
+ */
+ public String getSettingKey() {
+ return mSettingKey;
+ }
+
+ /**
+ * @return The value to write to settings to turn the feature on
+ */
+ public String getSettingOnValue() {
+ return mSettingOnValue;
+ }
+
+ /**
+ * @return The value to write to settings to turn the feature off
+ */
+ public String getSettingOffValue() {
+ return mSettingOffValue;
+ }
+
+ public String getLabel(Context context) {
+ return context.getString(mLabelStringResourceId);
+ }
+ }
+
// Class to allow mocking of static framework calls
public static class FrameworkObjectProvider {
public AccessibilityManager getAccessibilityManagerInstance(Context context) {
@@ -277,5 +395,9 @@
public Toast makeToastFromText(Context context, CharSequence charSequence, int duration) {
return Toast.makeText(context, charSequence, duration);
}
+
+ public Context getSystemUiContext() {
+ return ActivityThread.currentActivityThread().getSystemUiContext();
+ }
}
}
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index 0a539f1..8016a65 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -111,14 +111,7 @@
@Override
public void onClick(DialogInterface dialog, int which) {
if (mReason == UNLAUNCHABLE_REASON_QUIET_MODE && which == DialogInterface.BUTTON_POSITIVE) {
- if (UserManager.get(this).trySetQuietModeDisabled(mUserId, mTarget)
- && mTarget != null) {
- try {
- startIntentSenderForResult(mTarget, -1, null, 0, 0, 0);
- } catch (IntentSender.SendIntentException e) {
- /* ignore */
- }
- }
+ UserManager.get(this).trySetQuietModeDisabled(mUserId, mTarget);
}
}
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index fbdf17d..6fb02b1 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -28,6 +28,7 @@
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.Log;
+import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -137,7 +138,7 @@
private final String mName;
private final String mPackage;
private final int mUid;
- private final int mVersion;
+ private final long mVersion;
private final DurationsTable mDurations;
private final PssTable mPssTable;
@@ -170,7 +171,7 @@
* Create a new top-level process state, for the initial case where there is only
* a single package running in a process. The initial state is not running.
*/
- public ProcessState(ProcessStats processStats, String pkg, int uid, int vers, String name) {
+ public ProcessState(ProcessStats processStats, String pkg, int uid, long vers, String name) {
mStats = processStats;
mName = name;
mCommonProcess = this;
@@ -186,7 +187,7 @@
* state. The current running state of the top-level process is also copied,
* marked as started running at 'now'.
*/
- public ProcessState(ProcessState commonProcess, String pkg, int uid, int vers, String name,
+ public ProcessState(ProcessState commonProcess, String pkg, int uid, long vers, String name,
long now) {
mStats = commonProcess.mStats;
mName = name;
@@ -238,7 +239,7 @@
return mUid;
}
- public int getVersion() {
+ public long getVersion() {
return mVersion;
}
@@ -546,7 +547,7 @@
// The array map is still pointing to a common process state
// that is now shared across packages. Update it to point to
// the new per-package state.
- SparseArray<PackageState> vpkg = mStats.mPackages.get(pkgName, mUid);
+ LongSparseArray<PackageState> vpkg = mStats.mPackages.get(pkgName, mUid);
if (vpkg == null) {
throw new IllegalStateException("Didn't find package " + pkgName
+ " / " + mUid);
@@ -584,7 +585,7 @@
// The array map is still pointing to a common process state
// that is now shared across packages. Update it to point to
// the new per-package state.
- SparseArray<PackageState> vpkg = mStats.mPackages.get(pkgList.keyAt(index),
+ LongSparseArray<PackageState> vpkg = mStats.mPackages.get(pkgList.keyAt(index),
proc.mUid);
if (vpkg == null) {
throw new IllegalStateException("No existing package "
@@ -1037,7 +1038,7 @@
}
}
- public void dumpPackageProcCheckin(PrintWriter pw, String pkgName, int uid, int vers,
+ public void dumpPackageProcCheckin(PrintWriter pw, String pkgName, int uid, long vers,
String itemName, long now) {
pw.print("pkgproc,");
pw.print(pkgName);
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index 14f5e5b..2ce7936 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -28,6 +28,7 @@
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.Log;
+import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -157,7 +158,7 @@
};
// Current version of the parcel format.
- private static final int PARCEL_VERSION = 21;
+ private static final int PARCEL_VERSION = 22;
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
private static final int MAGIC = 0x50535454;
@@ -165,9 +166,8 @@
public String mTimePeriodStartClockStr;
public int mFlags;
- public final ProcessMap<SparseArray<PackageState>> mPackages
- = new ProcessMap<SparseArray<PackageState>>();
- public final ProcessMap<ProcessState> mProcesses = new ProcessMap<ProcessState>();
+ public final ProcessMap<LongSparseArray<PackageState>> mPackages = new ProcessMap<>();
+ public final ProcessMap<ProcessState> mProcesses = new ProcessMap<>();
public final long[] mMemFactorDurations = new long[ADJ_COUNT];
public int mMemFactor = STATE_NOTHING;
@@ -218,15 +218,16 @@
}
public void add(ProcessStats other) {
- ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = other.mPackages.getMap();
+ ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+ other.mPackages.getMap();
for (int ip=0; ip<pkgMap.size(); ip++) {
final String pkgName = pkgMap.keyAt(ip);
- final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
for (int iu=0; iu<uids.size(); iu++) {
final int uid = uids.keyAt(iu);
- final SparseArray<PackageState> versions = uids.valueAt(iu);
+ final LongSparseArray<PackageState> versions = uids.valueAt(iu);
for (int iv=0; iv<versions.size(); iv++) {
- final int vers = versions.keyAt(iv);
+ final long vers = versions.keyAt(iv);
final PackageState otherState = versions.valueAt(iv);
final int NPROCS = otherState.mProcesses.size();
final int NSRVS = otherState.mServices.size();
@@ -269,7 +270,7 @@
ProcessState otherProc = uids.valueAt(iu);
final String name = otherProc.getName();
final String pkg = otherProc.getPackage();
- final int vers = otherProc.getVersion();
+ final long vers = otherProc.getVersion();
ProcessState thisProc = mProcesses.get(name, uid);
if (DEBUG) Slog.d(TAG, "Adding uid " + uid + " proc " + name);
if (thisProc == null) {
@@ -420,11 +421,12 @@
// Next reset or prune all per-package processes, and for the ones that are reset
// track this back to the common processes.
- final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+ final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+ mPackages.getMap();
for (int ip=pkgMap.size()-1; ip>=0; ip--) {
- final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
for (int iu=uids.size()-1; iu>=0; iu--) {
- final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+ final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
for (int iv=vpkgs.size()-1; iv>=0; iv--) {
final PackageState pkgState = vpkgs.valueAt(iv);
for (int iproc=pkgState.mProcesses.size()-1; iproc>=0; iproc--) {
@@ -727,13 +729,14 @@
uids.valueAt(iu).commitStateTime(now);
}
}
- final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+ final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+ mPackages.getMap();
final int NPKG = pkgMap.size();
for (int ip=0; ip<NPKG; ip++) {
- final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
final int NUID = uids.size();
for (int iu=0; iu<NUID; iu++) {
- final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+ final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
final int NVERS = vpkgs.size();
for (int iv=0; iv<NVERS; iv++) {
PackageState pkgState = vpkgs.valueAt(iv);
@@ -781,23 +784,23 @@
out.writeInt(uids.keyAt(iu));
final ProcessState proc = uids.valueAt(iu);
writeCommonString(out, proc.getPackage());
- out.writeInt(proc.getVersion());
+ out.writeLong(proc.getVersion());
proc.writeToParcel(out, now);
}
}
out.writeInt(NPKG);
for (int ip=0; ip<NPKG; ip++) {
writeCommonString(out, pkgMap.keyAt(ip));
- final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
final int NUID = uids.size();
out.writeInt(NUID);
for (int iu=0; iu<NUID; iu++) {
out.writeInt(uids.keyAt(iu));
- final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+ final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
final int NVERS = vpkgs.size();
out.writeInt(NVERS);
for (int iv=0; iv<NVERS; iv++) {
- out.writeInt(vpkgs.keyAt(iv));
+ out.writeLong(vpkgs.keyAt(iv));
final PackageState pkgState = vpkgs.valueAt(iv);
final int NPROCS = pkgState.mProcesses.size();
out.writeInt(NPROCS);
@@ -963,7 +966,7 @@
mReadError = "bad process package name";
return;
}
- final int vers = in.readInt();
+ final long vers = in.readLong();
ProcessState proc = hadData ? mProcesses.get(procName, uid) : null;
if (proc != null) {
if (!proc.readFromParcel(in, false)) {
@@ -1014,11 +1017,11 @@
}
while (NVERS > 0) {
NVERS--;
- final int vers = in.readInt();
+ final long vers = in.readLong();
PackageState pkgState = new PackageState(pkgName, uid);
- SparseArray<PackageState> vpkg = mPackages.get(pkgName, uid);
+ LongSparseArray<PackageState> vpkg = mPackages.get(pkgName, uid);
if (vpkg == null) {
- vpkg = new SparseArray<PackageState>();
+ vpkg = new LongSparseArray<>();
mPackages.put(pkgName, uid, vpkg);
}
vpkg.put(vers, pkgState);
@@ -1117,10 +1120,10 @@
if (DEBUG_PARCEL) Slog.d(TAG, "Successfully read procstats!");
}
- public PackageState getPackageStateLocked(String packageName, int uid, int vers) {
- SparseArray<PackageState> vpkg = mPackages.get(packageName, uid);
+ public PackageState getPackageStateLocked(String packageName, int uid, long vers) {
+ LongSparseArray<PackageState> vpkg = mPackages.get(packageName, uid);
if (vpkg == null) {
- vpkg = new SparseArray<PackageState>();
+ vpkg = new LongSparseArray<PackageState>();
mPackages.put(packageName, uid, vpkg);
}
PackageState as = vpkg.get(vers);
@@ -1132,7 +1135,7 @@
return as;
}
- public ProcessState getProcessStateLocked(String packageName, int uid, int vers,
+ public ProcessState getProcessStateLocked(String packageName, int uid, long vers,
String processName) {
final PackageState pkgState = getPackageStateLocked(packageName, uid, vers);
ProcessState ps = pkgState.mProcesses.get(processName);
@@ -1202,7 +1205,7 @@
return ps;
}
- public ServiceState getServiceStateLocked(String packageName, int uid, int vers,
+ public ServiceState getServiceStateLocked(String packageName, int uid, long vers,
String processName, String className) {
final ProcessStats.PackageState as = getPackageStateLocked(packageName, uid, vers);
ServiceState ss = as.mServices.get(className);
@@ -1228,16 +1231,16 @@
mSysMemUsage.dump(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ);
sepNeeded = true;
}
- ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+ ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap = mPackages.getMap();
boolean printedHeader = false;
for (int ip=0; ip<pkgMap.size(); ip++) {
final String pkgName = pkgMap.keyAt(ip);
- final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
for (int iu=0; iu<uids.size(); iu++) {
final int uid = uids.keyAt(iu);
- final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+ final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
for (int iv=0; iv<vpkgs.size(); iv++) {
- final int vers = vpkgs.keyAt(iv);
+ final long vers = vpkgs.keyAt(iv);
final PackageState pkgState = vpkgs.valueAt(iv);
final int NPROCS = pkgState.mProcesses.size();
final int NSRVS = pkgState.mServices.size();
@@ -1531,12 +1534,13 @@
int[] procStates, int sortProcStates[], long now, String reqPackage,
boolean activeOnly) {
final ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>();
- final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+ final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+ mPackages.getMap();
for (int ip=0; ip<pkgMap.size(); ip++) {
final String pkgName = pkgMap.keyAt(ip);
- final SparseArray<SparseArray<PackageState>> procs = pkgMap.valueAt(ip);
+ final SparseArray<LongSparseArray<PackageState>> procs = pkgMap.valueAt(ip);
for (int iu=0; iu<procs.size(); iu++) {
- final SparseArray<PackageState> vpkgs = procs.valueAt(iu);
+ final LongSparseArray<PackageState> vpkgs = procs.valueAt(iu);
final int NVERS = vpkgs.size();
for (int iv=0; iv<NVERS; iv++) {
final PackageState state = vpkgs.valueAt(iv);
@@ -1571,7 +1575,8 @@
public void dumpCheckinLocked(PrintWriter pw, String reqPackage) {
final long now = SystemClock.uptimeMillis();
- final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+ final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+ mPackages.getMap();
pw.println("vers,5");
pw.print("period,"); pw.print(mTimePeriodStartClockStr);
pw.print(","); pw.print(mTimePeriodStartRealtime); pw.print(",");
@@ -1602,12 +1607,12 @@
if (reqPackage != null && !reqPackage.equals(pkgName)) {
continue;
}
- final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
for (int iu=0; iu<uids.size(); iu++) {
final int uid = uids.keyAt(iu);
- final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+ final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
for (int iv=0; iv<vpkgs.size(); iv++) {
- final int vers = vpkgs.keyAt(iv);
+ final long vers = vpkgs.keyAt(iv);
final PackageState pkgState = vpkgs.valueAt(iv);
final int NPROCS = pkgState.mProcesses.size();
final int NSRVS = pkgState.mServices.size();
@@ -1709,7 +1714,8 @@
}
public void toProto(ProtoOutputStream proto, long now) {
- final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+ final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+ mPackages.getMap();
proto.write(ProcessStatsSectionProto.START_REALTIME_MS, mTimePeriodStartRealtime);
proto.write(ProcessStatsSectionProto.END_REALTIME_MS,
@@ -1750,10 +1756,10 @@
}
final public static class ProcessStateHolder {
- public final int appVersion;
+ public final long appVersion;
public ProcessState state;
- public ProcessStateHolder(int _appVersion) {
+ public ProcessStateHolder(long _appVersion) {
appVersion = _appVersion;
}
}
diff --git a/core/java/com/android/internal/app/procstats/ServiceState.java b/core/java/com/android/internal/app/procstats/ServiceState.java
index 2e11c43..650de2ea 100644
--- a/core/java/com/android/internal/app/procstats/ServiceState.java
+++ b/core/java/com/android/internal/app/procstats/ServiceState.java
@@ -441,7 +441,7 @@
return totalTime;
}
- public void dumpTimesCheckin(PrintWriter pw, String pkgName, int uid, int vers,
+ public void dumpTimesCheckin(PrintWriter pw, String pkgName, int uid, long vers,
String serviceName, long now) {
dumpTimeCheckin(pw, "pkgsvc-run", pkgName, uid, vers, serviceName,
ServiceState.SERVICE_RUN, mRunCount, mRunState, mRunStartTime, now);
@@ -454,7 +454,7 @@
}
private void dumpTimeCheckin(PrintWriter pw, String label, String packageName,
- int uid, int vers, String serviceName, int serviceType, int opCount,
+ int uid, long vers, String serviceName, int serviceType, int opCount,
int curState, long curStartTime, long now) {
if (opCount <= 0) {
return;
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index 98f5bea..147438c 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -94,7 +94,7 @@
* "live" backup services without interfering with the live bookkeeping. The
* returned string should be a name that is expected to be unambiguous among all
* available backup transports; the name of the class implementing the transport
- * is a good choice.
+ * is a good choice. This MUST be constant.
*
* @return A unique name, suitable for use as a file or directory name, that the
* Backup Manager could use to disambiguate state files associated with
diff --git a/core/java/com/android/internal/content/ReferrerIntent.java b/core/java/com/android/internal/content/ReferrerIntent.java
index 8d9a1cf..76dcc9b 100644
--- a/core/java/com/android/internal/content/ReferrerIntent.java
+++ b/core/java/com/android/internal/content/ReferrerIntent.java
@@ -19,6 +19,8 @@
import android.content.Intent;
import android.os.Parcel;
+import java.util.Objects;
+
/**
* Subclass of Intent that also contains referrer (as a package name) information.
*/
@@ -48,4 +50,21 @@
return new ReferrerIntent[size];
}
};
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || !(obj instanceof ReferrerIntent)) {
+ return false;
+ }
+ final ReferrerIntent other = (ReferrerIntent) obj;
+ return filterEquals(other) && Objects.equals(mReferrer, other.mReferrer);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + filterHashCode();
+ result = 31 * result + Objects.hashCode(mReferrer);
+ return result;
+ }
}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 3e231d0..57efae6 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -836,7 +836,6 @@
private final Resources mRes;
private final ContentResolver mResolver;
private final HashMap<String, InputMethodInfo> mMethodMap;
- private final ArrayList<InputMethodInfo> mMethodList;
/**
* On-memory data store to emulate when {@link #mCopyOnWrite} is {@code true}.
@@ -906,7 +905,6 @@
mRes = res;
mResolver = resolver;
mMethodMap = methodMap;
- mMethodList = methodList;
switchCurrentUser(userId, copyOnWrite);
}
@@ -1087,7 +1085,7 @@
final ArrayList<InputMethodInfo> res = new ArrayList<>();
for (Pair<String, ArrayList<String>> ims: imsList) {
InputMethodInfo info = mMethodMap.get(ims.first);
- if (info != null) {
+ if (info != null && !info.isVrOnly()) {
res.add(info);
}
}
diff --git a/core/java/com/android/internal/logging/EventLogTags.logtags b/core/java/com/android/internal/logging/EventLogTags.logtags
index 93d5a03..a440ee4 100644
--- a/core/java/com/android/internal/logging/EventLogTags.logtags
+++ b/core/java/com/android/internal/logging/EventLogTags.logtags
@@ -8,3 +8,8 @@
524292 sysui_multi_action (content|4)
524290 sysui_count (name|3),(increment|1)
524291 sysui_histogram (name|3),(bucket|1)
+
+# ---------------------------
+# LatencyTracker.java
+# ---------------------------
+36070 sysui_latency (action|1|6),(latency|1|3)
diff --git a/core/java/com/android/internal/os/BackgroundThread.java b/core/java/com/android/internal/os/BackgroundThread.java
index cffba01..7558f8c 100644
--- a/core/java/com/android/internal/os/BackgroundThread.java
+++ b/core/java/com/android/internal/os/BackgroundThread.java
@@ -35,7 +35,7 @@
if (sInstance == null) {
sInstance = new BackgroundThread();
sInstance.start();
- sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
sHandler = new Handler(sInstance.getLooper());
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 6ede72d..a050a3c 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -120,7 +120,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 169 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 170 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS;
@@ -4389,6 +4389,7 @@
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mMobileRadioPowerState = powerState;
+ StatsLog.write(StatsLog.MOBILE_RADIO_POWER_STATE_CHANGED, uid, powerState);
if (active) {
mMobileRadioActiveTimer.startRunningLocked(elapsedRealtime);
mMobileRadioActivePerAppTimer.startRunningLocked(elapsedRealtime);
@@ -4426,7 +4427,7 @@
}
}
- public void noteDeviceIdleModeLocked(int mode, String activeReason, int activeUid) {
+ public void noteDeviceIdleModeLocked(final int mode, String activeReason, int activeUid) {
final long elapsedRealtime = mClocks.elapsedRealtime();
final long uptime = mClocks.uptimeMillis();
boolean nowIdling = mode == DEVICE_IDLE_MODE_DEEP;
@@ -4445,6 +4446,13 @@
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_ACTIVE,
activeReason, activeUid);
}
+ if (mDeviceIdling != nowIdling || mDeviceLightIdling != nowLightIdling) {
+ int statsmode;
+ if (nowIdling) statsmode = DEVICE_IDLE_MODE_DEEP;
+ else if (nowLightIdling) statsmode = DEVICE_IDLE_MODE_LIGHT;
+ else statsmode = DEVICE_IDLE_MODE_OFF;
+ StatsLog.write(StatsLog.DEVICE_IDLING_MODE_STATE_CHANGED, statsmode);
+ }
if (mDeviceIdling != nowIdling) {
mDeviceIdling = nowIdling;
int stepState = nowIdling ? STEP_LEVEL_MODE_DEVICE_IDLE : 0;
@@ -4489,14 +4497,16 @@
mDeviceIdleModeFullTimer.startRunningLocked(elapsedRealtime);
}
mDeviceIdleMode = mode;
+ StatsLog.write(StatsLog.DEVICE_IDLE_MODE_STATE_CHANGED, mode);
}
}
- public void notePackageInstalledLocked(String pkgName, int versionCode) {
+ public void notePackageInstalledLocked(String pkgName, long versionCode) {
final long elapsedRealtime = mClocks.elapsedRealtime();
final long uptime = mClocks.uptimeMillis();
+ // XXX need to figure out what to do with long version codes.
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PACKAGE_INSTALLED,
- pkgName, versionCode);
+ pkgName, (int)versionCode);
PackageChange pc = new PackageChange();
pc.mPackageName = pkgName;
pc.mUpdate = true;
@@ -5085,6 +5095,7 @@
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mWifiRadioPowerState = powerState;
+ StatsLog.write(StatsLog.WIFI_RADIO_POWER_STATE_CHANGED, uid, powerState);
}
}
@@ -6020,6 +6031,11 @@
}
@Override
+ public Timer getMulticastWakelockStats() {
+ return mWifiMulticastTimer;
+ }
+
+ @Override
public ArrayMap<String, ? extends BatteryStats.Timer> getSyncStats() {
return mSyncStats.getMap();
}
@@ -8923,8 +8939,6 @@
}
if (type == WAKE_TYPE_PARTIAL) {
createAggregatedPartialWakelockTimerLocked().startRunningLocked(elapsedRealtimeMs);
- // TODO(statsd): Possibly use a worksource instead of a uid.
- StatsLog.write(StatsLog.UID_WAKELOCK_STATE_CHANGED, getUid(), type, 1);
if (pid >= 0) {
Pid p = getPidStatsLocked(pid);
if (p.mWakeNesting++ == 0) {
@@ -8947,11 +8961,6 @@
if (type == WAKE_TYPE_PARTIAL) {
if (mAggregatedPartialWakelockTimer != null) {
mAggregatedPartialWakelockTimer.stopRunningLocked(elapsedRealtimeMs);
- if (!mAggregatedPartialWakelockTimer.isRunningLocked()) {
- // TODO(statsd): Possibly use a worksource instead of a uid.
- StatsLog.write(StatsLog.UID_WAKELOCK_STATE_CHANGED, getUid(), type,
- 0);
- }
}
if (pid >= 0) {
Pid p = mPids.get(pid);
@@ -9275,7 +9284,7 @@
if (pc.mUpdate) {
out.startTag(null, "upd");
out.attribute(null, "pkg", pc.mPackageName);
- out.attribute(null, "ver", Integer.toString(pc.mVersionCode));
+ out.attribute(null, "ver", Long.toString(pc.mVersionCode));
out.endTag(null, "upd");
} else {
out.startTag(null, "rem");
@@ -9404,7 +9413,7 @@
pc.mUpdate = true;
pc.mPackageName = parser.getAttributeValue(null, "pkg");
String verStr = parser.getAttributeValue(null, "ver");
- pc.mVersionCode = verStr != null ? Integer.parseInt(verStr) : 0;
+ pc.mVersionCode = verStr != null ? Long.parseLong(verStr) : 0;
dit.mPackageChanges.add(pc);
XmlUtils.skipCurrentTag(parser);
} else if (tagName.equals("rem")) {
@@ -12105,7 +12114,7 @@
PackageChange pc = new PackageChange();
pc.mPackageName = in.readString();
pc.mUpdate = in.readInt() != 0;
- pc.mVersionCode = in.readInt();
+ pc.mVersionCode = in.readLong();
mDailyPackageChanges.add(pc);
}
} else {
@@ -12530,7 +12539,7 @@
PackageChange pc = mDailyPackageChanges.get(i);
out.writeString(pc.mPackageName);
out.writeInt(pc.mUpdate ? 1 : 0);
- out.writeInt(pc.mVersionCode);
+ out.writeLong(pc.mVersionCode);
}
} else {
out.writeInt(0);
diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java
index 8fb56d4..d9aa325 100644
--- a/core/java/com/android/internal/os/SomeArgs.java
+++ b/core/java/com/android/internal/os/SomeArgs.java
@@ -48,6 +48,7 @@
public Object arg6;
public Object arg7;
public Object arg8;
+ public Object arg9;
public int argi1;
public int argi2;
public int argi3;
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index bab0306aa..5ec9094 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -113,6 +113,11 @@
void showGlobalActionsMenu();
/**
+ * Notifies the status bar that a new rotation suggestion is available.
+ */
+ void onProposedRotationChanged(int rotation);
+
+ /**
* Set whether the top app currently hides the statusbar.
*
* @param hidesStatusBar whether it is being hidden
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 22bfcc3..aa85668 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -292,6 +292,15 @@
return array;
}
+ public static @Nullable long[] convertToLongArray(@Nullable int[] intArray) {
+ if (intArray == null) return null;
+ long[] array = new long[intArray.length];
+ for (int i = 0; i < intArray.length; i++) {
+ array[i] = (long) intArray[i];
+ }
+ return array;
+ }
+
/**
* Adds value to given array if not already present, providing set-like
* behavior.
@@ -425,14 +434,17 @@
* Adds value to given array if not already present, providing set-like
* behavior.
*/
- public static @NonNull long[] appendLong(@Nullable long[] cur, long val) {
+ public static @NonNull long[] appendLong(@Nullable long[] cur, long val,
+ boolean allowDuplicates) {
if (cur == null) {
return new long[] { val };
}
final int N = cur.length;
- for (int i = 0; i < N; i++) {
- if (cur[i] == val) {
- return cur;
+ if (!allowDuplicates) {
+ for (int i = 0; i < N; i++) {
+ if (cur[i] == val) {
+ return cur;
+ }
}
}
long[] ret = new long[N + 1];
@@ -442,6 +454,14 @@
}
/**
+ * Adds value to given array if not already present, providing set-like
+ * behavior.
+ */
+ public static @NonNull long[] appendLong(@Nullable long[] cur, long val) {
+ return appendLong(cur, val, false);
+ }
+
+ /**
* Removes value from given array if present, providing set-like behavior.
*/
public static @Nullable long[] removeLong(@Nullable long[] cur, long val) {
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index f0b47de..f983de1 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -30,7 +30,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Set;
-import java.util.function.*;
+import java.util.function.Function;
import java.util.stream.Stream;
/**
diff --git a/core/java/com/android/internal/util/FunctionalUtils.java b/core/java/com/android/internal/util/FunctionalUtils.java
index cdef97e..eb92c1c 100644
--- a/core/java/com/android/internal/util/FunctionalUtils.java
+++ b/core/java/com/android/internal/util/FunctionalUtils.java
@@ -32,7 +32,7 @@
*/
@FunctionalInterface
public interface ThrowingRunnable {
- void run() throws Exception;
+ void runOrThrow() throws Exception;
}
/**
@@ -43,7 +43,7 @@
*/
@FunctionalInterface
public interface ThrowingSupplier<T> {
- T get() throws Exception;
+ T getOrThrow() throws Exception;
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
similarity index 86%
rename from packages/SystemUI/src/com/android/keyguard/LatencyTracker.java
rename to core/java/com/android/internal/util/LatencyTracker.java
index cee0afc..72cd248 100644
--- a/packages/SystemUI/src/com/android/keyguard/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -1,20 +1,18 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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
+ * 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
+ * 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.keyguard;
+package com.android.internal.util;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -28,7 +26,7 @@
import android.util.Log;
import android.util.SparseLongArray;
-import com.android.systemui.EventLogTags;
+import com.android.internal.logging.EventLogTags;
/**
* Class to track various latencies in SystemUI. It then outputs the latency to logcat so these
@@ -76,13 +74,19 @@
*/
public static final int ACTION_TURN_ON_SCREEN = 5;
+ /**
+ * Time it takes to rotate the screen.
+ */
+ public static final int ACTION_ROTATE_SCREEN = 6;
+
private static final String[] NAMES = new String[] {
"expand panel",
"toggle recents",
"fingerprint wake-and-unlock",
"check credential",
"check credential unlocked",
- "turn on screen" };
+ "turn on screen",
+ "rotate the screen"};
private static LatencyTracker sLatencyTracker;
diff --git a/core/java/com/android/internal/util/RingBuffer.java b/core/java/com/android/internal/util/RingBuffer.java
index c22be2c..9a6e542 100644
--- a/core/java/com/android/internal/util/RingBuffer.java
+++ b/core/java/com/android/internal/util/RingBuffer.java
@@ -60,6 +60,25 @@
mBuffer[indexOf(mCursor++)] = t;
}
+ /**
+ * Returns object of type <T> at the next writable slot, creating one if it is not already
+ * available. In case of any errors while creating the object, <code>null</code> will
+ * be returned.
+ */
+ public T getNextSlot() {
+ final int nextSlotIdx = indexOf(mCursor++);
+ T item = mBuffer[nextSlotIdx];
+ if (item == null) {
+ try {
+ item = (T) mBuffer.getClass().getComponentType().newInstance();
+ } catch (IllegalAccessException | InstantiationException e) {
+ return null;
+ }
+ mBuffer[nextSlotIdx] = item;
+ }
+ return item;
+ }
+
public T[] toArray() {
// Only generic way to create a T[] from another T[]
T[] out = Arrays.copyOf(mBuffer, size(), (Class<T[]>) mBuffer.getClass());
diff --git a/core/java/com/android/internal/util/UserIcons.java b/core/java/com/android/internal/util/UserIcons.java
index daf745f..bfe4323 100644
--- a/core/java/com/android/internal/util/UserIcons.java
+++ b/core/java/com/android/internal/util/UserIcons.java
@@ -61,17 +61,19 @@
* Returns a default user icon for the given user.
*
* Note that for guest users, you should pass in {@code UserHandle.USER_NULL}.
+ *
+ * @param resources resources object to fetch user icon / color.
* @param userId the user id or {@code UserHandle.USER_NULL} for a non-user specific icon
* @param light whether we want a light icon (suitable for a dark background)
*/
- public static Drawable getDefaultUserIcon(int userId, boolean light) {
+ public static Drawable getDefaultUserIcon(Resources resources, int userId, boolean light) {
int colorResId = light ? R.color.user_icon_default_white : R.color.user_icon_default_gray;
if (userId != UserHandle.USER_NULL) {
// Return colored icon instead
colorResId = USER_ICON_COLORS[userId % USER_ICON_COLORS.length];
}
- Drawable icon = Resources.getSystem().getDrawable(R.drawable.ic_account_circle, null).mutate();
- icon.setColorFilter(Resources.getSystem().getColor(colorResId, null), Mode.SRC_IN);
+ Drawable icon = resources.getDrawable(R.drawable.ic_account_circle, null).mutate();
+ icon.setColorFilter(resources.getColor(colorResId, null), Mode.SRC_IN);
icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
return icon;
}
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/core/java/com/android/internal/util/function/QuadConsumer.java
similarity index 67%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to core/java/com/android/internal/util/function/QuadConsumer.java
index 4ccdea5..d899c01 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/core/java/com/android/internal/util/function/QuadConsumer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,11 +14,16 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+package com.android.internal.util.function;
-import android.telephony.SubscriptionInfo;
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
+import java.util.function.Consumer;
+
+/**
+ * A 4-argument {@link Consumer}
+ *
+ * @hide
+ */
+public interface QuadConsumer<A, B, C, D> {
+ void accept(A a, B b, C c, D d);
}
-
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/core/java/com/android/internal/util/function/QuadFunction.java
similarity index 67%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to core/java/com/android/internal/util/function/QuadFunction.java
index 4ccdea5..700d953 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/core/java/com/android/internal/util/function/QuadFunction.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,11 +14,16 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+package com.android.internal.util.function;
-import android.telephony.SubscriptionInfo;
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
+import java.util.function.Function;
+
+/**
+ * A 4-argument {@link Function}
+ *
+ * @hide
+ */
+public interface QuadFunction<A, B, C, D, R> {
+ R apply(A a, B b, C c, D d);
}
-
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/core/java/com/android/internal/util/function/QuadPredicate.java
similarity index 67%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to core/java/com/android/internal/util/function/QuadPredicate.java
index 4ccdea5..512c98b 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/core/java/com/android/internal/util/function/QuadPredicate.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,11 +14,16 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+package com.android.internal.util.function;
-import android.telephony.SubscriptionInfo;
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
+import java.util.function.Predicate;
+
+/**
+ * A 4-argument {@link Predicate}
+ *
+ * @hide
+ */
+public interface QuadPredicate<A, B, C, D> {
+ boolean test(A a, B b, C c, D d);
}
-
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/core/java/com/android/internal/util/function/TriConsumer.java
similarity index 68%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to core/java/com/android/internal/util/function/TriConsumer.java
index 4ccdea5..40d614e 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/core/java/com/android/internal/util/function/TriConsumer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,11 +14,16 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+package com.android.internal.util.function;
-import android.telephony.SubscriptionInfo;
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
+import java.util.function.Consumer;
+
+/**
+ * A 3-argument {@link Consumer}
+ *
+ * @hide
+ */
+public interface TriConsumer<A, B, C> {
+ void accept(A a, B b, C c);
}
-
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/core/java/com/android/internal/util/function/TriFunction.java
similarity index 68%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to core/java/com/android/internal/util/function/TriFunction.java
index 4ccdea5..2b1df86 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/core/java/com/android/internal/util/function/TriFunction.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,11 +14,16 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+package com.android.internal.util.function;
-import android.telephony.SubscriptionInfo;
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
+import java.util.function.Function;
+
+/**
+ * A 3-argument {@link Function}
+ *
+ * @hide
+ */
+public interface TriFunction<A, B, C, R> {
+ R apply(A a, B b, C c);
}
-
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/core/java/com/android/internal/util/function/TriPredicate.java
similarity index 67%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to core/java/com/android/internal/util/function/TriPredicate.java
index 4ccdea5..d9cd968 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/core/java/com/android/internal/util/function/TriPredicate.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,11 +14,16 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+package com.android.internal.util.function;
-import android.telephony.SubscriptionInfo;
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
+import java.util.function.Predicate;
+
+/**
+ * A 3-argument {@link Predicate}
+ *
+ * @hide
+ */
+public interface TriPredicate<A, B, C> {
+ boolean test(A a, B b, C c);
}
-
diff --git a/core/java/android/service/autofill/IAuthenticationCallback.aidl b/core/java/com/android/internal/util/function/pooled/ArgumentPlaceholder.java
similarity index 63%
rename from core/java/android/service/autofill/IAuthenticationCallback.aidl
rename to core/java/com/android/internal/util/function/pooled/ArgumentPlaceholder.java
index 36b989d..cf86b71 100644
--- a/core/java/android/service/autofill/IAuthenticationCallback.aidl
+++ b/core/java/com/android/internal/util/function/pooled/ArgumentPlaceholder.java
@@ -14,18 +14,20 @@
* limitations under the License.
*/
-package android.view.autofill;
-
-import android.view.autofill.Dataset;
-import android.service.autofill.FillResponse;
+package com.android.internal.util.function.pooled;
/**
- * Callback for delivering authentication result.
+ * A placeholder for an argument of type {@code R}
*
- * {@hide}
+ * @see PooledLambda
+ * @hide
*/
-interface IAutoFillAuthCallback {
- void onSuccessForDataset(in Dataset dataset);
- void onSuccessForFillResponse(in FillResponse response);
- void onFailure(CharSequence message);
+public final class ArgumentPlaceholder<R> {
+ private ArgumentPlaceholder() {}
+ static final ArgumentPlaceholder<?> INSTANCE = new ArgumentPlaceholder<>();
+
+ @Override
+ public String toString() {
+ return "_";
+ }
}
diff --git a/core/java/com/android/internal/util/function/pooled/OmniFunction.java b/core/java/com/android/internal/util/function/pooled/OmniFunction.java
new file mode 100755
index 0000000..c0f506e
--- /dev/null
+++ b/core/java/com/android/internal/util/function/pooled/OmniFunction.java
@@ -0,0 +1,132 @@
+/*
+ * 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.internal.util.function.pooled;
+
+import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
+import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
+import com.android.internal.util.function.QuadConsumer;
+import com.android.internal.util.function.QuadFunction;
+import com.android.internal.util.function.TriConsumer;
+import com.android.internal.util.function.TriFunction;
+
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BiPredicate;
+import java.util.function.Function;
+
+/**
+ * An interface implementing all supported function interfaces, delegating each to {@link #invoke}
+ *
+ * @hide
+ */
+abstract class OmniFunction<A, B, C, D, R> implements
+ PooledFunction<A, R>, BiFunction<A, B, R>, TriFunction<A, B, C, R>,
+ QuadFunction<A, B, C, D, R>,
+ PooledConsumer<A>, BiConsumer<A, B>, TriConsumer<A, B, C>, QuadConsumer<A, B, C, D>,
+ PooledPredicate<A>, BiPredicate<A, B>,
+ PooledSupplier<R>, PooledRunnable,
+ ThrowingRunnable, ThrowingSupplier<R>,
+ PooledSupplier.OfInt, PooledSupplier.OfLong, PooledSupplier.OfDouble {
+
+ abstract R invoke(A a, B b, C c, D d);
+
+ @Override
+ public R apply(A o, B o2) {
+ return invoke(o, o2, null, null);
+ }
+
+ @Override
+ public R apply(A o) {
+ return invoke(o, null, null, null);
+ }
+
+ abstract public <V> OmniFunction<A, B, C, D, V> andThen(Function<? super R, ? extends V> after);
+ abstract public OmniFunction<A, B, C, D, R> negate();
+
+ @Override
+ public void accept(A o, B o2) {
+ invoke(o, o2, null, null);
+ }
+
+ @Override
+ public void accept(A o) {
+ invoke(o, null, null, null);
+ }
+
+ @Override
+ public void run() {
+ invoke(null, null, null, null);
+ }
+
+ @Override
+ public R get() {
+ return invoke(null, null, null, null);
+ }
+
+ @Override
+ public boolean test(A o, B o2) {
+ return (Boolean) invoke(o, o2, null, null);
+ }
+
+ @Override
+ public boolean test(A o) {
+ return (Boolean) invoke(o, null, null, null);
+ }
+
+ @Override
+ public PooledRunnable asRunnable() {
+ return this;
+ }
+
+ @Override
+ public PooledConsumer<A> asConsumer() {
+ return this;
+ }
+
+ @Override
+ public R apply(A a, B b, C c) {
+ return invoke(a, b, c, null);
+ }
+
+ @Override
+ public void accept(A a, B b, C c) {
+ invoke(a, b, c, null);
+ }
+
+ @Override
+ public R apply(A a, B b, C c, D d) {
+ return invoke(a, b, c, d);
+ }
+
+ @Override
+ public void accept(A a, B b, C c, D d) {
+ invoke(a, b, c, d);
+ }
+
+ @Override
+ public void runOrThrow() throws Exception {
+ run();
+ }
+
+ @Override
+ public R getOrThrow() throws Exception {
+ return get();
+ }
+
+ @Override
+ abstract public OmniFunction<A, B, C, D, R> recycleOnUse();
+}
diff --git a/core/java/android/print/IPrintClient.aidl b/core/java/com/android/internal/util/function/pooled/PooledConsumer.java
similarity index 63%
rename from core/java/android/print/IPrintClient.aidl
rename to core/java/com/android/internal/util/function/pooled/PooledConsumer.java
index 3f39d08..f66586e 100644
--- a/core/java/android/print/IPrintClient.aidl
+++ b/core/java/com/android/internal/util/function/pooled/PooledConsumer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -14,17 +14,18 @@
* limitations under the License.
*/
-package android.print;
+package com.android.internal.util.function.pooled;
-import android.content.IntentSender;
+import java.util.function.Consumer;
/**
- * Interface for communication with a printing app.
+ * {@link Consumer} + {@link PooledLambda}
*
- * @see android.print.IPrintClientCallback
- *
+ * @see PooledLambda
* @hide
*/
-oneway interface IPrintClient {
- void startPrintJobConfigActivity(in IntentSender intent);
+public interface PooledConsumer<T> extends PooledLambda, Consumer<T> {
+
+ /** @inheritDoc */
+ PooledConsumer<T> recycleOnUse();
}
diff --git a/core/java/android/service/autofill/IAuthenticationCallback.aidl b/core/java/com/android/internal/util/function/pooled/PooledFunction.java
similarity index 61%
copy from core/java/android/service/autofill/IAuthenticationCallback.aidl
copy to core/java/com/android/internal/util/function/pooled/PooledFunction.java
index 36b989d..1f166fa 100644
--- a/core/java/android/service/autofill/IAuthenticationCallback.aidl
+++ b/core/java/com/android/internal/util/function/pooled/PooledFunction.java
@@ -14,18 +14,23 @@
* limitations under the License.
*/
-package android.view.autofill;
+package com.android.internal.util.function.pooled;
-import android.view.autofill.Dataset;
-import android.service.autofill.FillResponse;
+import java.util.function.Function;
/**
- * Callback for delivering authentication result.
+ * {@link Function} + {@link PooledLambda}
*
- * {@hide}
+ * @see PooledLambda
+ * @hide
*/
-interface IAutoFillAuthCallback {
- void onSuccessForDataset(in Dataset dataset);
- void onSuccessForFillResponse(in FillResponse response);
- void onFailure(CharSequence message);
+public interface PooledFunction<A, R> extends PooledLambda, Function<A, R> {
+
+ /**
+ * Ignores the result
+ */
+ PooledConsumer<A> asConsumer();
+
+ /** @inheritDoc */
+ PooledFunction<A, R> recycleOnUse();
}
diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambda.java b/core/java/com/android/internal/util/function/pooled/PooledLambda.java
new file mode 100755
index 0000000..17b140d
--- /dev/null
+++ b/core/java/com/android/internal/util/function/pooled/PooledLambda.java
@@ -0,0 +1,813 @@
+/*
+ * 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.internal.util.function.pooled;
+
+import static com.android.internal.util.function.pooled.PooledLambdaImpl.acquire;
+import static com.android.internal.util.function.pooled.PooledLambdaImpl.acquireConstSupplier;
+
+import android.os.Message;
+
+import com.android.internal.util.function.QuadConsumer;
+import com.android.internal.util.function.QuadFunction;
+import com.android.internal.util.function.TriConsumer;
+import com.android.internal.util.function.TriFunction;
+import com.android.internal.util.function.pooled.PooledLambdaImpl.LambdaType.ReturnType;
+
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/**
+ * A recyclable anonymous function.
+ * Allows obtaining {@link Function}s/{@link Runnable}s/{@link Supplier}s/etc. without allocating a
+ * new instance each time
+ *
+ * This exploits the mechanic that stateless lambdas (such as plain/non-bound method references)
+ * get translated into a singleton instance, making it possible to create a recyclable container
+ * ({@link PooledLambdaImpl}) holding a reference to such a singleton function, as well as
+ * (possibly partial) arguments required for its invocation.
+ *
+ * To obtain an instance, use one of the factory methods in this class.
+ *
+ * You can call {@link #recycleOnUse} to make the instance automatically recycled upon invocation,
+ * making if effectively <b>one-time use</b>.
+ * This is often the behavior you want, as it allows to not worry about manual recycling.
+ * Some notable examples: {@link android.os.Handler#post(Runnable)},
+ * {@link android.app.Activity#runOnUiThread(Runnable)}, {@link android.view.View#post(Runnable)}
+ *
+ * For factories of functions that take further arguments, the corresponding 'missing' argument's
+ * position is marked by an argument of type {@link ArgumentPlaceholder} with the type parameter
+ * corresponding to missing argument's type.
+ * You can fill the 'missing argument' spot with {@link #__()}
+ * (which is the factory function for {@link ArgumentPlaceholder})
+ *
+ * @hide
+ */
+@SuppressWarnings({"unchecked", "unused", "WeakerAccess"})
+public interface PooledLambda {
+
+ /**
+ * Recycles this instance. No-op if already recycled.
+ */
+ void recycle();
+
+ /**
+ * Makes this instance automatically {@link #recycle} itself after the first call.
+ *
+ * @return this instance for convenience
+ */
+ PooledLambda recycleOnUse();
+
+
+ // Factories
+
+ /**
+ * @return {@link ArgumentPlaceholder} with the inferred type parameter value
+ */
+ static <R> ArgumentPlaceholder<R> __() {
+ return (ArgumentPlaceholder<R>) ArgumentPlaceholder.INSTANCE;
+ }
+
+ /**
+ * @param typeHint the explicitly specified type of the missing argument
+ * @return {@link ArgumentPlaceholder} with the specified type parameter value
+ */
+ static <R> ArgumentPlaceholder<R> __(Class<R> typeHint) {
+ return __();
+ }
+
+ /**
+ * Wraps the given value into a {@link PooledSupplier}
+ *
+ * @param value a value to wrap
+ * @return a pooled supplier of {@code value}
+ */
+ static <R> PooledSupplier<R> obtainSupplier(R value) {
+ PooledLambdaImpl r = acquireConstSupplier(ReturnType.OBJECT);
+ r.mFunc = value;
+ return r;
+ }
+
+ /**
+ * Wraps the given value into a {@link PooledSupplier}
+ *
+ * @param value a value to wrap
+ * @return a pooled supplier of {@code value}
+ */
+ static PooledSupplier.OfInt obtainSupplier(int value) {
+ PooledLambdaImpl r = acquireConstSupplier(ReturnType.INT);
+ r.mConstValue = value;
+ return r;
+ }
+
+ /**
+ * Wraps the given value into a {@link PooledSupplier}
+ *
+ * @param value a value to wrap
+ * @return a pooled supplier of {@code value}
+ */
+ static PooledSupplier.OfLong obtainSupplier(long value) {
+ PooledLambdaImpl r = acquireConstSupplier(ReturnType.LONG);
+ r.mConstValue = value;
+ return r;
+ }
+
+ /**
+ * Wraps the given value into a {@link PooledSupplier}
+ *
+ * @param value a value to wrap
+ * @return a pooled supplier of {@code value}
+ */
+ static PooledSupplier.OfDouble obtainSupplier(double value) {
+ PooledLambdaImpl r = acquireConstSupplier(ReturnType.DOUBLE);
+ r.mConstValue = Double.doubleToRawLongBits(value);
+ return r;
+ }
+
+ /**
+ * {@link PooledRunnable} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @return a {@link PooledRunnable}, equivalent to lambda:
+ * {@code () -> function(arg1) }
+ */
+ static <A> PooledRunnable obtainRunnable(
+ Consumer<? super A> function,
+ A arg1) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 1, 0, ReturnType.VOID, arg1, null, null, null);
+ }
+
+ /**
+ * {@link PooledSupplier} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @return a {@link PooledSupplier}, equivalent to lambda:
+ * {@code () -> function(arg1) }
+ */
+ static <A> PooledSupplier<Boolean> obtainSupplier(
+ Predicate<? super A> function,
+ A arg1) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 1, 0, ReturnType.BOOLEAN, arg1, null, null, null);
+ }
+
+ /**
+ * {@link PooledSupplier} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @return a {@link PooledSupplier}, equivalent to lambda:
+ * {@code () -> function(arg1) }
+ */
+ static <A, R> PooledSupplier<R> obtainSupplier(
+ Function<? super A, ? extends R> function,
+ A arg1) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 1, 0, ReturnType.OBJECT, arg1, null, null, null);
+ }
+
+ /**
+ * Factory of {@link Message}s that contain an
+ * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
+ * {@link Message#getCallback internal callback}.
+ *
+ * The callback is equivalent to one obtainable via
+ * {@link #obtainRunnable(Consumer, Object)}
+ *
+ * Note that using this method with {@link android.os.Handler#handleMessage}
+ * is more efficient than the alternative of {@link android.os.Handler#post}
+ * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points
+ * when obtaining {@link Message} and {@link PooledRunnable} from pools separately
+ *
+ * You may optionally set a {@link Message#what} for the message if you want to be
+ * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise
+ * there's no need to do so
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @return a {@link Message} invoking {@code function(arg1) } when handled
+ */
+ static <A> Message obtainMessage(
+ Consumer<? super A> function,
+ A arg1) {
+ synchronized (Message.sPoolSync) {
+ PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
+ function, 1, 0, ReturnType.VOID, arg1, null, null, null);
+ return Message.obtain().setCallback(callback.recycleOnUse());
+ }
+ }
+
+ /**
+ * {@link PooledRunnable} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @return a {@link PooledRunnable}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2) }
+ */
+ static <A, B> PooledRunnable obtainRunnable(
+ BiConsumer<? super A, ? super B> function,
+ A arg1, B arg2) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 2, 0, ReturnType.VOID, arg1, arg2, null, null);
+ }
+
+ /**
+ * {@link PooledSupplier} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @return a {@link PooledSupplier}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2) }
+ */
+ static <A, B> PooledSupplier<Boolean> obtainSupplier(
+ BiPredicate<? super A, ? super B> function,
+ A arg1, B arg2) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 2, 0, ReturnType.BOOLEAN, arg1, arg2, null, null);
+ }
+
+ /**
+ * {@link PooledSupplier} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @return a {@link PooledSupplier}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2) }
+ */
+ static <A, B, R> PooledSupplier<R> obtainSupplier(
+ BiFunction<? super A, ? super B, ? extends R> function,
+ A arg1, B arg2) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 2, 0, ReturnType.OBJECT, arg1, arg2, null, null);
+ }
+
+ /**
+ * {@link PooledConsumer} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg2 parameter supplied to {@code function} on call
+ * @return a {@link PooledConsumer}, equivalent to lambda:
+ * {@code (arg1) -> function(arg1, arg2) }
+ */
+ static <A, B> PooledConsumer<A> obtainConsumer(
+ BiConsumer<? super A, ? super B> function,
+ ArgumentPlaceholder<A> arg1, B arg2) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 2, 1, ReturnType.VOID, arg1, arg2, null, null);
+ }
+
+ /**
+ * {@link PooledPredicate} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg2 parameter supplied to {@code function} on call
+ * @return a {@link PooledPredicate}, equivalent to lambda:
+ * {@code (arg1) -> function(arg1, arg2) }
+ */
+ static <A, B> PooledPredicate<A> obtainPredicate(
+ BiPredicate<? super A, ? super B> function,
+ ArgumentPlaceholder<A> arg1, B arg2) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null);
+ }
+
+ /**
+ * {@link PooledFunction} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg2 parameter supplied to {@code function} on call
+ * @return a {@link PooledFunction}, equivalent to lambda:
+ * {@code (arg1) -> function(arg1, arg2) }
+ */
+ static <A, B, R> PooledFunction<A, R> obtainFunction(
+ BiFunction<? super A, ? super B, ? extends R> function,
+ ArgumentPlaceholder<A> arg1, B arg2) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null);
+ }
+
+ /**
+ * {@link PooledConsumer} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 placeholder for a missing argument. Use {@link #__} to get one
+ * @return a {@link PooledConsumer}, equivalent to lambda:
+ * {@code (arg2) -> function(arg1, arg2) }
+ */
+ static <A, B> PooledConsumer<B> obtainConsumer(
+ BiConsumer<? super A, ? super B> function,
+ A arg1, ArgumentPlaceholder<B> arg2) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 2, 1, ReturnType.VOID, arg1, arg2, null, null);
+ }
+
+ /**
+ * {@link PooledPredicate} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 placeholder for a missing argument. Use {@link #__} to get one
+ * @return a {@link PooledPredicate}, equivalent to lambda:
+ * {@code (arg2) -> function(arg1, arg2) }
+ */
+ static <A, B> PooledPredicate<B> obtainPredicate(
+ BiPredicate<? super A, ? super B> function,
+ A arg1, ArgumentPlaceholder<B> arg2) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null);
+ }
+
+ /**
+ * {@link PooledFunction} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 placeholder for a missing argument. Use {@link #__} to get one
+ * @return a {@link PooledFunction}, equivalent to lambda:
+ * {@code (arg2) -> function(arg1, arg2) }
+ */
+ static <A, B, R> PooledFunction<B, R> obtainFunction(
+ BiFunction<? super A, ? super B, ? extends R> function,
+ A arg1, ArgumentPlaceholder<B> arg2) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null);
+ }
+
+ /**
+ * Factory of {@link Message}s that contain an
+ * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
+ * {@link Message#getCallback internal callback}.
+ *
+ * The callback is equivalent to one obtainable via
+ * {@link #obtainRunnable(BiConsumer, Object, Object)}
+ *
+ * Note that using this method with {@link android.os.Handler#handleMessage}
+ * is more efficient than the alternative of {@link android.os.Handler#post}
+ * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points
+ * when obtaining {@link Message} and {@link PooledRunnable} from pools separately
+ *
+ * You may optionally set a {@link Message#what} for the message if you want to be
+ * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise
+ * there's no need to do so
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @return a {@link Message} invoking {@code function(arg1, arg2) } when handled
+ */
+ static <A, B> Message obtainMessage(
+ BiConsumer<? super A, ? super B> function,
+ A arg1, B arg2) {
+ synchronized (Message.sPoolSync) {
+ PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
+ function, 2, 0, ReturnType.VOID, arg1, arg2, null, null);
+ return Message.obtain().setCallback(callback.recycleOnUse());
+ }
+ }
+
+ /**
+ * {@link PooledRunnable} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @return a {@link PooledRunnable}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2, arg3) }
+ */
+ static <A, B, C> PooledRunnable obtainRunnable(
+ TriConsumer<? super A, ? super B, ? super C> function,
+ A arg1, B arg2, C arg3) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null);
+ }
+
+ /**
+ * {@link PooledSupplier} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @return a {@link PooledSupplier}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2, arg3) }
+ */
+ static <A, B, C, R> PooledSupplier<R> obtainSupplier(
+ TriFunction<? super A, ? super B, ? super C, ? extends R> function,
+ A arg1, B arg2, C arg3) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 3, 0, ReturnType.OBJECT, arg1, arg2, arg3, null);
+ }
+
+ /**
+ * {@link PooledConsumer} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @return a {@link PooledConsumer}, equivalent to lambda:
+ * {@code (arg1) -> function(arg1, arg2, arg3) }
+ */
+ static <A, B, C> PooledConsumer<A> obtainConsumer(
+ TriConsumer<? super A, ? super B, ? super C> function,
+ ArgumentPlaceholder<A> arg1, B arg2, C arg3) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null);
+ }
+
+ /**
+ * {@link PooledFunction} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @return a {@link PooledFunction}, equivalent to lambda:
+ * {@code (arg1) -> function(arg1, arg2, arg3) }
+ */
+ static <A, B, C, R> PooledFunction<A, R> obtainFunction(
+ TriFunction<? super A, ? super B, ? super C, ? extends R> function,
+ ArgumentPlaceholder<A> arg1, B arg2, C arg3) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null);
+ }
+
+ /**
+ * {@link PooledConsumer} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg3 parameter supplied to {@code function} on call
+ * @return a {@link PooledConsumer}, equivalent to lambda:
+ * {@code (arg2) -> function(arg1, arg2, arg3) }
+ */
+ static <A, B, C> PooledConsumer<B> obtainConsumer(
+ TriConsumer<? super A, ? super B, ? super C> function,
+ A arg1, ArgumentPlaceholder<B> arg2, C arg3) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null);
+ }
+
+ /**
+ * {@link PooledFunction} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg3 parameter supplied to {@code function} on call
+ * @return a {@link PooledFunction}, equivalent to lambda:
+ * {@code (arg2) -> function(arg1, arg2, arg3) }
+ */
+ static <A, B, C, R> PooledFunction<B, R> obtainFunction(
+ TriFunction<? super A, ? super B, ? super C, ? extends R> function,
+ A arg1, ArgumentPlaceholder<B> arg2, C arg3) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null);
+ }
+
+ /**
+ * {@link PooledConsumer} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 placeholder for a missing argument. Use {@link #__} to get one
+ * @return a {@link PooledConsumer}, equivalent to lambda:
+ * {@code (arg3) -> function(arg1, arg2, arg3) }
+ */
+ static <A, B, C> PooledConsumer<C> obtainConsumer(
+ TriConsumer<? super A, ? super B, ? super C> function,
+ A arg1, B arg2, ArgumentPlaceholder<C> arg3) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null);
+ }
+
+ /**
+ * {@link PooledFunction} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 placeholder for a missing argument. Use {@link #__} to get one
+ * @return a {@link PooledFunction}, equivalent to lambda:
+ * {@code (arg3) -> function(arg1, arg2, arg3) }
+ */
+ static <A, B, C, R> PooledFunction<C, R> obtainFunction(
+ TriFunction<? super A, ? super B, ? super C, ? extends R> function,
+ A arg1, B arg2, ArgumentPlaceholder<C> arg3) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null);
+ }
+
+ /**
+ * Factory of {@link Message}s that contain an
+ * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
+ * {@link Message#getCallback internal callback}.
+ *
+ * The callback is equivalent to one obtainable via
+ * {@link #obtainRunnable(TriConsumer, Object, Object, Object)}
+ *
+ * Note that using this method with {@link android.os.Handler#handleMessage}
+ * is more efficient than the alternative of {@link android.os.Handler#post}
+ * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points
+ * when obtaining {@link Message} and {@link PooledRunnable} from pools separately
+ *
+ * You may optionally set a {@link Message#what} for the message if you want to be
+ * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise
+ * there's no need to do so
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @return a {@link Message} invoking {@code function(arg1, arg2, arg3) } when handled
+ */
+ static <A, B, C> Message obtainMessage(
+ TriConsumer<? super A, ? super B, ? super C> function,
+ A arg1, B arg2, C arg3) {
+ synchronized (Message.sPoolSync) {
+ PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
+ function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null);
+ return Message.obtain().setCallback(callback.recycleOnUse());
+ }
+ }
+
+ /**
+ * {@link PooledRunnable} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @return a {@link PooledRunnable}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D> PooledRunnable obtainRunnable(
+ QuadConsumer<? super A, ? super B, ? super C, ? super D> function,
+ A arg1, B arg2, C arg3, D arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * {@link PooledSupplier} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @return a {@link PooledSupplier}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D, R> PooledSupplier<R> obtainSupplier(
+ QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
+ A arg1, B arg2, C arg3, D arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * {@link PooledConsumer} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @return a {@link PooledConsumer}, equivalent to lambda:
+ * {@code (arg1) -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D> PooledConsumer<A> obtainConsumer(
+ QuadConsumer<? super A, ? super B, ? super C, ? super D> function,
+ ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * {@link PooledFunction} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @return a {@link PooledFunction}, equivalent to lambda:
+ * {@code (arg1) -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D, R> PooledFunction<A, R> obtainFunction(
+ QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
+ ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * {@link PooledConsumer} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @return a {@link PooledConsumer}, equivalent to lambda:
+ * {@code (arg2) -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D> PooledConsumer<B> obtainConsumer(
+ QuadConsumer<? super A, ? super B, ? super C, ? super D> function,
+ A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * {@link PooledFunction} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @return a {@link PooledFunction}, equivalent to lambda:
+ * {@code (arg2) -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D, R> PooledFunction<B, R> obtainFunction(
+ QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
+ A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * {@link PooledConsumer} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg4 parameter supplied to {@code function} on call
+ * @return a {@link PooledConsumer}, equivalent to lambda:
+ * {@code (arg3) -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D> PooledConsumer<C> obtainConsumer(
+ QuadConsumer<? super A, ? super B, ? super C, ? super D> function,
+ A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * {@link PooledFunction} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg4 parameter supplied to {@code function} on call
+ * @return a {@link PooledFunction}, equivalent to lambda:
+ * {@code (arg3) -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D, R> PooledFunction<C, R> obtainFunction(
+ QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
+ A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * {@link PooledConsumer} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 placeholder for a missing argument. Use {@link #__} to get one
+ * @return a {@link PooledConsumer}, equivalent to lambda:
+ * {@code (arg4) -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D> PooledConsumer<D> obtainConsumer(
+ QuadConsumer<? super A, ? super B, ? super C, ? super D> function,
+ A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * {@link PooledFunction} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 placeholder for a missing argument. Use {@link #__} to get one
+ * @return a {@link PooledFunction}, equivalent to lambda:
+ * {@code (arg4) -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D, R> PooledFunction<D, R> obtainFunction(
+ QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
+ A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * Factory of {@link Message}s that contain an
+ * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
+ * {@link Message#getCallback internal callback}.
+ *
+ * The callback is equivalent to one obtainable via
+ * {@link #obtainRunnable(QuadConsumer, Object, Object, Object, Object)}
+ *
+ * Note that using this method with {@link android.os.Handler#handleMessage}
+ * is more efficient than the alternative of {@link android.os.Handler#post}
+ * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points
+ * when obtaining {@link Message} and {@link PooledRunnable} from pools separately
+ *
+ * You may optionally set a {@link Message#what} for the message if you want to be
+ * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise
+ * there's no need to do so
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @return a {@link Message} invoking {@code function(arg1, arg2, arg3, arg4) } when handled
+ */
+ static <A, B, C, D> Message obtainMessage(
+ QuadConsumer<? super A, ? super B, ? super C, ? super D> function,
+ A arg1, B arg2, C arg3, D arg4) {
+ synchronized (Message.sPoolSync) {
+ PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
+ function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4);
+ return Message.obtain().setCallback(callback.recycleOnUse());
+ }
+ }
+}
diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
new file mode 100755
index 0000000..03e013c
--- /dev/null
+++ b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
@@ -0,0 +1,557 @@
+/*
+ * 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.internal.util.function.pooled;
+
+import android.annotation.Nullable;
+import android.os.Message;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pools;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.BitUtils;
+import com.android.internal.util.function.QuadConsumer;
+import com.android.internal.util.function.QuadFunction;
+import com.android.internal.util.function.QuadPredicate;
+import com.android.internal.util.function.TriConsumer;
+import com.android.internal.util.function.TriFunction;
+import com.android.internal.util.function.TriPredicate;
+
+import java.util.Arrays;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/**
+ * @see PooledLambda
+ * @hide
+ */
+final class PooledLambdaImpl<R> extends OmniFunction<Object, Object, Object, Object, R> {
+
+ private static final boolean DEBUG = false;
+ private static final String LOG_TAG = "PooledLambdaImpl";
+
+ private static final int MAX_ARGS = 4;
+
+ private static final int MAX_POOL_SIZE = 50;
+
+ static class Pool extends Pools.SynchronizedPool<PooledLambdaImpl> {
+
+ public Pool(Object lock) {
+ super(MAX_POOL_SIZE, lock);
+ }
+ }
+
+ static final Pool sPool = new Pool(new Object());
+ static final Pool sMessageCallbacksPool = new Pool(Message.sPoolSync);
+
+ private PooledLambdaImpl() {}
+
+ /**
+ * The function reference to be invoked
+ *
+ * May be the return value itself in case when an immediate result constant is provided instead
+ */
+ Object mFunc;
+
+ /**
+ * A primitive result value to be immediately returned on invocation instead of calling
+ * {@link #mFunc}
+ */
+ long mConstValue;
+
+ /**
+ * Arguments for {@link #mFunc}
+ */
+ @Nullable Object[] mArgs = null;
+
+ /**
+ * Flag for {@link #mFlags}
+ *
+ * Indicates whether this instance is recycled
+ */
+ private static final int FLAG_RECYCLED = 1 << MAX_ARGS;
+
+ /**
+ * Flag for {@link #mFlags}
+ *
+ * Indicates whether this instance should be immediately recycled on invocation
+ * (as requested via {@link PooledLambda#recycleOnUse()}) or not(default)
+ */
+ private static final int FLAG_RECYCLE_ON_USE = 1 << (MAX_ARGS + 1);
+
+ /**
+ * Flag for {@link #mFlags}
+ *
+ * Indicates that this instance was acquired from {@link #sMessageCallbacksPool} as opposed to
+ * {@link #sPool}
+ */
+ private static final int FLAG_ACQUIRED_FROM_MESSAGE_CALLBACKS_POOL = 1 << (MAX_ARGS + 2);
+
+ /** @see #mFlags */
+ static final int MASK_EXPOSED_AS = LambdaType.MASK << (MAX_ARGS + 3);
+
+ /** @see #mFlags */
+ static final int MASK_FUNC_TYPE = LambdaType.MASK <<
+ (MAX_ARGS + 3 + LambdaType.MASK_BIT_COUNT);
+
+ /**
+ * Bit schema:
+ * AAAABCDEEEEEEFFFFFF
+ *
+ * Where:
+ * A - whether {@link #mArgs arg} at corresponding index was specified at
+ * {@link #acquire creation time} (0) or {@link #invoke invocation time} (1)
+ * B - {@link #FLAG_RECYCLED}
+ * C - {@link #FLAG_RECYCLE_ON_USE}
+ * D - {@link #FLAG_ACQUIRED_FROM_MESSAGE_CALLBACKS_POOL}
+ * E - {@link LambdaType} representing the type of the lambda returned to the caller from a
+ * factory method
+ * F - {@link LambdaType} of {@link #mFunc} as resolved when calling a factory method
+ */
+ int mFlags = 0;
+
+
+ @Override
+ public void recycle() {
+ if (DEBUG) Log.i(LOG_TAG, this + ".recycle()");
+ if (!isRecycled()) doRecycle();
+ }
+
+ private void doRecycle() {
+ if (DEBUG) Log.i(LOG_TAG, this + ".doRecycle()");
+ Pool pool = (mFlags & FLAG_ACQUIRED_FROM_MESSAGE_CALLBACKS_POOL) != 0
+ ? PooledLambdaImpl.sMessageCallbacksPool
+ : PooledLambdaImpl.sPool;
+
+ mFunc = null;
+ if (mArgs != null) Arrays.fill(mArgs, null);
+ mFlags = FLAG_RECYCLED;
+ mConstValue = 0L;
+
+ pool.release(this);
+ }
+
+ @Override
+ R invoke(Object a1, Object a2, Object a3, Object a4) {
+ checkNotRecycled();
+ if (DEBUG) {
+ Log.i(LOG_TAG, this + ".invoke("
+ + commaSeparateFirstN(
+ new Object[] { a1, a2, a3, a4 },
+ LambdaType.decodeArgCount(getFlags(MASK_EXPOSED_AS)))
+ + ")");
+ }
+ boolean ignored = fillInArg(a1) && fillInArg(a2) && fillInArg(a3) && fillInArg(a4);
+ int argCount = LambdaType.decodeArgCount(getFlags(MASK_FUNC_TYPE));
+ if (argCount != LambdaType.MASK_ARG_COUNT) {
+ for (int i = 0; i < argCount; i++) {
+ if (mArgs[i] == ArgumentPlaceholder.INSTANCE) {
+ throw new IllegalStateException("Missing argument #" + i + " among "
+ + Arrays.toString(mArgs));
+ }
+ }
+ }
+ try {
+ return doInvoke();
+ } finally {
+ if (isRecycleOnUse()) doRecycle();
+ if (!isRecycled()) {
+ int argsSize = ArrayUtils.size(mArgs);
+ for (int i = 0; i < argsSize; i++) {
+ popArg(i);
+ }
+ }
+ }
+ }
+
+ private boolean fillInArg(Object invocationArg) {
+ int argsSize = ArrayUtils.size(mArgs);
+ for (int i = 0; i < argsSize; i++) {
+ if (mArgs[i] == ArgumentPlaceholder.INSTANCE) {
+ mArgs[i] = invocationArg;
+ mFlags |= BitUtils.bitAt(i);
+ return true;
+ }
+ }
+ if (invocationArg != null && invocationArg != ArgumentPlaceholder.INSTANCE) {
+ throw new IllegalStateException("No more arguments expected for provided arg "
+ + invocationArg + " among " + Arrays.toString(mArgs));
+ }
+ return false;
+ }
+
+ private void checkNotRecycled() {
+ if (isRecycled()) throw new IllegalStateException("Instance is recycled: " + this);
+ }
+
+ @SuppressWarnings("unchecked")
+ private R doInvoke() {
+ final int funcType = getFlags(MASK_FUNC_TYPE);
+ final int argCount = LambdaType.decodeArgCount(funcType);
+ final int returnType = LambdaType.decodeReturnType(funcType);
+
+ switch (argCount) {
+ case LambdaType.MASK_ARG_COUNT: {
+ switch (returnType) {
+ case LambdaType.ReturnType.INT: return (R) (Integer) getAsInt();
+ case LambdaType.ReturnType.LONG: return (R) (Long) getAsLong();
+ case LambdaType.ReturnType.DOUBLE: return (R) (Double) getAsDouble();
+ default: return (R) mFunc;
+ }
+ }
+ case 0: {
+ switch (returnType) {
+ case LambdaType.ReturnType.VOID: {
+ ((Runnable) mFunc).run();
+ return null;
+ }
+ case LambdaType.ReturnType.BOOLEAN:
+ case LambdaType.ReturnType.OBJECT: {
+ return (R) ((Supplier) mFunc).get();
+ }
+ }
+ } break;
+ case 1: {
+ switch (returnType) {
+ case LambdaType.ReturnType.VOID: {
+ ((Consumer) mFunc).accept(popArg(0));
+ return null;
+ }
+ case LambdaType.ReturnType.BOOLEAN: {
+ return (R) (Object) ((Predicate) mFunc).test(popArg(0));
+ }
+ case LambdaType.ReturnType.OBJECT: {
+ return (R) ((Function) mFunc).apply(popArg(0));
+ }
+ }
+ } break;
+ case 2: {
+ switch (returnType) {
+ case LambdaType.ReturnType.VOID: {
+ ((BiConsumer) mFunc).accept(popArg(0), popArg(1));
+ return null;
+ }
+ case LambdaType.ReturnType.BOOLEAN: {
+ return (R) (Object) ((BiPredicate) mFunc).test(popArg(0), popArg(1));
+ }
+ case LambdaType.ReturnType.OBJECT: {
+ return (R) ((BiFunction) mFunc).apply(popArg(0), popArg(1));
+ }
+ }
+ } break;
+ case 3: {
+ switch (returnType) {
+ case LambdaType.ReturnType.VOID: {
+ ((TriConsumer) mFunc).accept(popArg(0), popArg(1), popArg(2));
+ return null;
+ }
+ case LambdaType.ReturnType.BOOLEAN: {
+ return (R) (Object) ((TriPredicate) mFunc).test(
+ popArg(0), popArg(1), popArg(2));
+ }
+ case LambdaType.ReturnType.OBJECT: {
+ return (R) ((TriFunction) mFunc).apply(popArg(0), popArg(1), popArg(2));
+ }
+ }
+ } break;
+ case 4: {
+ switch (returnType) {
+ case LambdaType.ReturnType.VOID: {
+ ((QuadConsumer) mFunc).accept(popArg(0), popArg(1), popArg(2), popArg(3));
+ return null;
+ }
+ case LambdaType.ReturnType.BOOLEAN: {
+ return (R) (Object) ((QuadPredicate) mFunc).test(
+ popArg(0), popArg(1), popArg(2), popArg(3));
+ }
+ case LambdaType.ReturnType.OBJECT: {
+ return (R) ((QuadFunction) mFunc).apply(
+ popArg(0), popArg(1), popArg(2), popArg(3));
+ }
+ }
+ } break;
+ }
+ throw new IllegalStateException("Unknown function type: " + LambdaType.toString(funcType));
+ }
+
+ private boolean isConstSupplier() {
+ return LambdaType.decodeArgCount(getFlags(MASK_FUNC_TYPE)) == LambdaType.MASK_ARG_COUNT;
+ }
+
+ private Object popArg(int index) {
+ Object result = mArgs[index];
+ if (isInvocationArgAtIndex(index)) {
+ mArgs[index] = ArgumentPlaceholder.INSTANCE;
+ mFlags &= ~BitUtils.bitAt(index);
+ }
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ if (isRecycled()) return "<recycled PooledLambda@" + hashCodeHex(this) + ">";
+
+ StringBuilder sb = new StringBuilder();
+ if (isConstSupplier()) {
+ sb.append(getFuncTypeAsString()).append("(").append(doInvoke()).append(")");
+ } else {
+ if (mFunc instanceof PooledLambdaImpl) {
+ sb.append(mFunc);
+ } else {
+ sb.append(getFuncTypeAsString()).append("@").append(hashCodeHex(mFunc));
+ }
+ sb.append("(");
+ sb.append(commaSeparateFirstN(mArgs, LambdaType.decodeArgCount(getFlags(MASK_FUNC_TYPE))));
+ sb.append(")");
+ }
+ return sb.toString();
+ }
+
+ private String commaSeparateFirstN(@Nullable Object[] arr, int n) {
+ if (arr == null) return "";
+ return TextUtils.join(",", Arrays.copyOf(arr, n));
+ }
+
+ private static String hashCodeHex(Object o) {
+ return Integer.toHexString(o.hashCode());
+ }
+
+ private String getFuncTypeAsString() {
+ if (isRecycled()) throw new IllegalStateException();
+ if (isConstSupplier()) return "supplier";
+ String name = LambdaType.toString(getFlags(MASK_EXPOSED_AS));
+ if (name.endsWith("Consumer")) return "consumer";
+ if (name.endsWith("Function")) return "function";
+ if (name.endsWith("Predicate")) return "predicate";
+ if (name.endsWith("Supplier")) return "supplier";
+ if (name.endsWith("Runnable")) return "runnable";
+ throw new IllegalStateException("Don't know the string representation of " + name);
+ }
+
+ /**
+ * Internal non-typesafe factory method for {@link PooledLambdaImpl}
+ */
+ static <E extends PooledLambda> E acquire(Pool pool, Object f,
+ int fNumArgs, int numPlaceholders, int fReturnType,
+ Object a, Object b, Object c, Object d) {
+ PooledLambdaImpl r = acquire(pool);
+ if (DEBUG) {
+ Log.i(LOG_TAG,
+ "acquire(this = @" + hashCodeHex(r)
+ + ", f = " + f
+ + ", fNumArgs = " + fNumArgs
+ + ", numPlaceholders = " + numPlaceholders
+ + ", fReturnType = " + LambdaType.ReturnType.toString(fReturnType)
+ + ", a = " + a
+ + ", b = " + b
+ + ", c = " + c
+ + ", d = " + d
+ + ")");
+ }
+ r.mFunc = f;
+ r.setFlags(MASK_FUNC_TYPE, LambdaType.encode(fNumArgs, fReturnType));
+ r.setFlags(MASK_EXPOSED_AS, LambdaType.encode(numPlaceholders, fReturnType));
+ if (ArrayUtils.size(r.mArgs) < fNumArgs) r.mArgs = new Object[fNumArgs];
+ setIfInBounds(r.mArgs, 0, a);
+ setIfInBounds(r.mArgs, 1, b);
+ setIfInBounds(r.mArgs, 2, c);
+ setIfInBounds(r.mArgs, 3, d);
+ return (E) r;
+ }
+
+ static PooledLambdaImpl acquireConstSupplier(int type) {
+ PooledLambdaImpl r = acquire(PooledLambdaImpl.sPool);
+ int lambdaType = LambdaType.encode(LambdaType.MASK_ARG_COUNT, type);
+ r.setFlags(PooledLambdaImpl.MASK_FUNC_TYPE, lambdaType);
+ r.setFlags(PooledLambdaImpl.MASK_EXPOSED_AS, lambdaType);
+ return r;
+ }
+
+ static PooledLambdaImpl acquire(Pool pool) {
+ PooledLambdaImpl r = pool.acquire();
+ if (r == null) r = new PooledLambdaImpl();
+ r.mFlags &= ~FLAG_RECYCLED;
+ r.setFlags(FLAG_ACQUIRED_FROM_MESSAGE_CALLBACKS_POOL,
+ pool == sMessageCallbacksPool ? 1 : 0);
+ return r;
+ }
+
+ private static void setIfInBounds(Object[] array, int i, Object a) {
+ if (i < ArrayUtils.size(array)) array[i] = a;
+ }
+
+ @Override
+ public OmniFunction<Object, Object, Object, Object, R> negate() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <V> OmniFunction<Object, Object, Object, Object, V> andThen(
+ Function<? super R, ? extends V> after) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public double getAsDouble() {
+ return Double.longBitsToDouble(mConstValue);
+ }
+
+ @Override
+ public int getAsInt() {
+ return (int) mConstValue;
+ }
+
+ @Override
+ public long getAsLong() {
+ return mConstValue;
+ }
+
+ @Override
+ public OmniFunction<Object, Object, Object, Object, R> recycleOnUse() {
+ if (DEBUG) Log.i(LOG_TAG, this + ".recycleOnUse()");
+ mFlags |= FLAG_RECYCLE_ON_USE;
+ return this;
+ }
+
+ private boolean isRecycled() {
+ return (mFlags & FLAG_RECYCLED) != 0;
+ }
+
+ private boolean isRecycleOnUse() {
+ return (mFlags & FLAG_RECYCLE_ON_USE) != 0;
+ }
+
+ private boolean isInvocationArgAtIndex(int argIndex) {
+ return (mFlags & (1 << argIndex)) != 0;
+ }
+
+ int getFlags(int mask) {
+ return unmask(mask, mFlags);
+ }
+
+ void setFlags(int mask, int value) {
+ mFlags &= ~mask;
+ mFlags |= mask(mask, value);
+ }
+
+ /**
+ * 0xFF000, 0xAB -> 0xAB000
+ */
+ private static int mask(int mask, int value) {
+ return (value << Integer.numberOfTrailingZeros(mask)) & mask;
+ }
+
+ /**
+ * 0xFF000, 0xAB123 -> 0xAB
+ */
+ private static int unmask(int mask, int bits) {
+ return (bits & mask) / (1 << Integer.numberOfTrailingZeros(mask));
+ }
+
+ /**
+ * Contract for encoding a supported lambda type in {@link #MASK_BIT_COUNT} bits
+ */
+ static class LambdaType {
+ public static final int MASK_ARG_COUNT = 0b111;
+ public static final int MASK_RETURN_TYPE = 0b111000;
+ public static final int MASK = MASK_ARG_COUNT | MASK_RETURN_TYPE;
+ public static final int MASK_BIT_COUNT = 6;
+
+ static int encode(int argCount, int returnType) {
+ return mask(MASK_ARG_COUNT, argCount) | mask(MASK_RETURN_TYPE, returnType);
+ }
+
+ static int decodeArgCount(int type) {
+ return type & MASK_ARG_COUNT;
+ }
+
+ static int decodeReturnType(int type) {
+ return unmask(MASK_RETURN_TYPE, type);
+ }
+
+ static String toString(int type) {
+ int argCount = decodeArgCount(type);
+ int returnType = decodeReturnType(type);
+ if (argCount == 0) {
+ if (returnType == ReturnType.VOID) return "Runnable";
+ if (returnType == ReturnType.OBJECT || returnType == ReturnType.BOOLEAN) {
+ return "Supplier";
+ }
+ }
+ return argCountPrefix(argCount) + ReturnType.lambdaSuffix(returnType);
+ }
+
+ private static String argCountPrefix(int argCount) {
+ switch (argCount) {
+ case MASK_ARG_COUNT: return "";
+ case 1: return "";
+ case 2: return "Bi";
+ case 3: return "Tri";
+ case 4: return "Quad";
+ default: throw new IllegalArgumentException("" + argCount);
+ }
+ }
+
+ static class ReturnType {
+ public static final int VOID = 1;
+ public static final int BOOLEAN = 2;
+ public static final int OBJECT = 3;
+ public static final int INT = 4;
+ public static final int LONG = 5;
+ public static final int DOUBLE = 6;
+
+ static String toString(int returnType) {
+ switch (returnType) {
+ case VOID: return "VOID";
+ case BOOLEAN: return "BOOLEAN";
+ case OBJECT: return "OBJECT";
+ case INT: return "INT";
+ case LONG: return "LONG";
+ case DOUBLE: return "DOUBLE";
+ default: return "" + returnType;
+ }
+ }
+
+ static String lambdaSuffix(int type) {
+ return prefix(type) + suffix(type);
+ }
+
+ private static String prefix(int type) {
+ switch (type) {
+ case INT: return "Int";
+ case LONG: return "Long";
+ case DOUBLE: return "Double";
+ default: return "";
+ }
+ }
+
+ private static String suffix(int type) {
+ switch (type) {
+ case VOID: return "Consumer";
+ case BOOLEAN: return "Predicate";
+ case OBJECT: return "Function";
+ default: return "Supplier";
+ }
+ }
+ }
+ }
+}
diff --git a/core/java/android/service/autofill/IAuthenticationCallback.aidl b/core/java/com/android/internal/util/function/pooled/PooledPredicate.java
similarity index 62%
copy from core/java/android/service/autofill/IAuthenticationCallback.aidl
copy to core/java/com/android/internal/util/function/pooled/PooledPredicate.java
index 36b989d..9b14366 100644
--- a/core/java/android/service/autofill/IAuthenticationCallback.aidl
+++ b/core/java/com/android/internal/util/function/pooled/PooledPredicate.java
@@ -14,18 +14,23 @@
* limitations under the License.
*/
-package android.view.autofill;
+package com.android.internal.util.function.pooled;
-import android.view.autofill.Dataset;
-import android.service.autofill.FillResponse;
+import java.util.function.Predicate;
/**
- * Callback for delivering authentication result.
+ * {@link Predicate} + {@link PooledLambda}
*
- * {@hide}
+ * @see PooledLambda
+ * @hide
*/
-interface IAutoFillAuthCallback {
- void onSuccessForDataset(in Dataset dataset);
- void onSuccessForFillResponse(in FillResponse response);
- void onFailure(CharSequence message);
+public interface PooledPredicate<T> extends PooledLambda, Predicate<T> {
+
+ /**
+ * Ignores the result
+ */
+ PooledConsumer<T> asConsumer();
+
+ /** @inheritDoc */
+ PooledPredicate<T> recycleOnUse();
}
diff --git a/core/java/android/service/autofill/IAuthenticationCallback.aidl b/core/java/com/android/internal/util/function/pooled/PooledRunnable.java
similarity index 63%
copy from core/java/android/service/autofill/IAuthenticationCallback.aidl
copy to core/java/com/android/internal/util/function/pooled/PooledRunnable.java
index 36b989d..89ca82e 100644
--- a/core/java/android/service/autofill/IAuthenticationCallback.aidl
+++ b/core/java/com/android/internal/util/function/pooled/PooledRunnable.java
@@ -14,18 +14,17 @@
* limitations under the License.
*/
-package android.view.autofill;
+package com.android.internal.util.function.pooled;
-import android.view.autofill.Dataset;
-import android.service.autofill.FillResponse;
+import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
/**
- * Callback for delivering authentication result.
+ * {@link Runnable} + {@link PooledLambda}
*
- * {@hide}
+ * @see PooledLambda
+ * @hide
*/
-interface IAutoFillAuthCallback {
- void onSuccessForDataset(in Dataset dataset);
- void onSuccessForFillResponse(in FillResponse response);
- void onFailure(CharSequence message);
+public interface PooledRunnable extends PooledLambda, Runnable, ThrowingRunnable {
+ /** @inheritDoc */
+ PooledRunnable recycleOnUse();
}
diff --git a/core/java/com/android/internal/util/function/pooled/PooledSupplier.java b/core/java/com/android/internal/util/function/pooled/PooledSupplier.java
new file mode 100644
index 0000000..dd7f73e
--- /dev/null
+++ b/core/java/com/android/internal/util/function/pooled/PooledSupplier.java
@@ -0,0 +1,59 @@
+/*
+ * 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.internal.util.function.pooled;
+
+import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
+
+import java.util.function.DoubleSupplier;
+import java.util.function.IntSupplier;
+import java.util.function.LongSupplier;
+import java.util.function.Supplier;
+
+/**
+ * {@link Supplier} + {@link PooledLambda}
+ *
+ * @see PooledLambda
+ * @hide
+ */
+public interface PooledSupplier<T> extends PooledLambda, Supplier<T>, ThrowingSupplier<T> {
+
+ /**
+ * Ignores the result
+ */
+ PooledRunnable asRunnable();
+
+ /** @inheritDoc */
+ PooledSupplier<T> recycleOnUse();
+
+ /** {@link PooledLambda} + {@link IntSupplier} */
+ interface OfInt extends IntSupplier, PooledLambda {
+ /** @inheritDoc */
+ PooledSupplier.OfInt recycleOnUse();
+ }
+
+ /** {@link PooledLambda} + {@link LongSupplier} */
+ interface OfLong extends LongSupplier, PooledLambda {
+ /** @inheritDoc */
+ PooledSupplier.OfLong recycleOnUse();
+ }
+
+ /** {@link PooledLambda} + {@link DoubleSupplier} */
+ interface OfDouble extends DoubleSupplier, PooledLambda {
+ /** @inheritDoc */
+ PooledSupplier.OfDouble recycleOnUse();
+ }
+}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 361fd3da..7178a0d 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -22,6 +22,7 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.MergedConfiguration;
+import android.view.DisplayCutout;
import android.view.DragEvent;
import android.view.IWindow;
import android.view.IWindowSession;
@@ -41,7 +42,8 @@
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
Rect stableInsets, Rect outsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
- boolean alwaysConsumeNavBar, int displayId) {
+ boolean alwaysConsumeNavBar, int displayId,
+ DisplayCutout.ParcelableWrapper displayCutout) {
if (reportDraw) {
try {
mSession.finishDrawing(this);
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index b979807..ca8624d 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -36,6 +36,7 @@
interface IInputMethodManager {
// TODO: Use ParceledListSlice instead
List<InputMethodInfo> getInputMethodList();
+ List<InputMethodInfo> getVrInputMethodList();
// TODO: Use ParceledListSlice instead
List<InputMethodInfo> getEnabledInputMethodList();
List<InputMethodSubtype> getEnabledInputMethodSubtypeList(in String imiId,
diff --git a/core/java/com/android/internal/view/RotationPolicy.java b/core/java/com/android/internal/view/RotationPolicy.java
index b479cb1..d7b9132 100644
--- a/core/java/com/android/internal/view/RotationPolicy.java
+++ b/core/java/com/android/internal/view/RotationPolicy.java
@@ -108,11 +108,19 @@
* Enables or disables rotation lock from the system UI toggle.
*/
public static void setRotationLock(Context context, final boolean enabled) {
+ final int rotation = areAllRotationsAllowed(context) ? CURRENT_ROTATION : NATURAL_ROTATION;
+ setRotationLockAtAngle(context, enabled, rotation);
+ }
+
+ /**
+ * Enables or disables rotation lock at a specific rotation from system UI.
+ */
+ public static void setRotationLockAtAngle(Context context, final boolean enabled,
+ final int rotation) {
Settings.System.putIntForUser(context.getContentResolver(),
Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0,
UserHandle.USER_CURRENT);
- final int rotation = areAllRotationsAllowed(context) ? CURRENT_ROTATION : NATURAL_ROTATION;
setRotationLock(enabled, rotation);
}
diff --git a/core/java/com/android/internal/view/TooltipPopup.java b/core/java/com/android/internal/view/TooltipPopup.java
index d38ea2c..24f0b0c 100644
--- a/core/java/com/android/internal/view/TooltipPopup.java
+++ b/core/java/com/android/internal/view/TooltipPopup.java
@@ -142,7 +142,7 @@
mTmpAnchorPos[1] -= mTmpAppPos[1];
// mTmpAnchorPos is now relative to the main app window.
- outParams.x = mTmpAnchorPos[0] + offsetX - mTmpDisplayFrame.width() / 2;
+ outParams.x = mTmpAnchorPos[0] + offsetX - appView.getWidth() / 2;
final int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
mContentView.measure(spec, spec);
@@ -157,6 +157,9 @@
outParams.y = yBelow;
}
} else {
+ // Use mTmpDisplayFrame.height() as the lower boundary instead of appView.getHeight(),
+ // as the latter includes the navigation bar, and tooltips do not look good over
+ // the navigation bar.
if (yBelow + tooltipHeight <= mTmpDisplayFrame.height()) {
outParams.y = yBelow;
} else {
diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java
index 26023b4..e013553 100644
--- a/core/java/com/android/internal/widget/NotificationActionListLayout.java
+++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java
@@ -21,6 +21,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.Gravity;
@@ -203,6 +204,11 @@
public void onViewAdded(View child) {
super.onViewAdded(child);
clearMeasureOrder();
+ // For some reason ripples + notification actions seem to be an unhappy combination
+ // b/69474443 so just turn them off for now.
+ if (child.getBackground() instanceof RippleDrawable) {
+ ((RippleDrawable)child.getBackground()).setForceSoftware(true);
+ }
}
@Override
diff --git a/core/java/com/android/internal/widget/RecyclerView.java b/core/java/com/android/internal/widget/RecyclerView.java
index 408a4e9..7abc76a 100644
--- a/core/java/com/android/internal/widget/RecyclerView.java
+++ b/core/java/com/android/internal/widget/RecyclerView.java
@@ -9556,7 +9556,7 @@
if (vScroll == 0 && hScroll == 0) {
return false;
}
- mRecyclerView.smoothScrollBy(hScroll, vScroll);
+ mRecyclerView.scrollBy(hScroll, vScroll);
return true;
}
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 17c7ebd..7635a72 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -81,6 +81,7 @@
private int mCollapsibleHeightReserved;
private int mTopOffset;
+ private boolean mShowAtTop;
private boolean mIsDragging;
private boolean mOpenOnClick;
@@ -134,6 +135,7 @@
mMaxCollapsedHeightSmall = a.getDimensionPixelSize(
R.styleable.ResolverDrawerLayout_maxCollapsedHeightSmall,
mMaxCollapsedHeight);
+ mShowAtTop = a.getBoolean(R.styleable.ResolverDrawerLayout_showAtTop, false);
a.recycle();
mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material);
@@ -162,6 +164,16 @@
return mCollapseOffset > 0;
}
+ public void setShowAtTop(boolean showOnTop) {
+ mShowAtTop = showOnTop;
+ invalidate();
+ requestLayout();
+ }
+
+ public boolean getShowAtTop() {
+ return mShowAtTop;
+ }
+
public void setCollapsed(boolean collapsed) {
if (!isLaidOut()) {
mOpenOnLayout = collapsed;
@@ -206,6 +218,12 @@
return false;
}
+ if (getShowAtTop()) {
+ // Keep the drawer fully open.
+ mCollapseOffset = 0;
+ return false;
+ }
+
if (isLaidOut()) {
final boolean isCollapsedOld = mCollapseOffset != 0;
if (remainClosed && (oldCollapsibleHeight < mCollapsibleHeight
@@ -372,14 +390,23 @@
mVelocityTracker.computeCurrentVelocity(1000);
final float yvel = mVelocityTracker.getYVelocity(mActivePointerId);
if (Math.abs(yvel) > mMinFlingVelocity) {
- if (isDismissable()
- && yvel > 0 && mCollapseOffset > mCollapsibleHeight) {
- smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, yvel);
- mDismissOnScrollerFinished = true;
+ if (getShowAtTop()) {
+ if (isDismissable() && yvel < 0) {
+ abortAnimation();
+ dismiss();
+ } else {
+ smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel);
+ }
} else {
- smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel);
+ if (isDismissable()
+ && yvel > 0 && mCollapseOffset > mCollapsibleHeight) {
+ smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, yvel);
+ mDismissOnScrollerFinished = true;
+ } else {
+ smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel);
+ }
}
- } else {
+ }else {
smoothScrollTo(
mCollapseOffset < mCollapsibleHeight / 2 ? 0 : mCollapsibleHeight, 0);
}
@@ -421,6 +448,11 @@
mVelocityTracker.clear();
}
+ private void dismiss() {
+ mRunOnDismissedListener = new RunOnDismissedListener();
+ post(mRunOnDismissedListener);
+ }
+
@Override
public void computeScroll() {
super.computeScroll();
@@ -430,8 +462,7 @@
if (keepGoing) {
postInvalidateOnAnimation();
} else if (mDismissOnScrollerFinished && mOnDismissedListener != null) {
- mRunOnDismissedListener = new RunOnDismissedListener();
- post(mRunOnDismissedListener);
+ dismiss();
}
}
}
@@ -443,6 +474,10 @@
}
private float performDrag(float dy) {
+ if (getShowAtTop()) {
+ return 0;
+ }
+
final float newPos = Math.max(0, Math.min(mCollapseOffset + dy,
mCollapsibleHeight + mUncollapsibleHeight));
if (newPos != mCollapseOffset) {
@@ -656,7 +691,7 @@
@Override
public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
- if (velocityY > mMinFlingVelocity && mCollapseOffset != 0) {
+ if (!getShowAtTop() && velocityY > mMinFlingVelocity && mCollapseOffset != 0) {
smoothScrollTo(0, velocityY);
return true;
}
@@ -666,12 +701,21 @@
@Override
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
if (!consumed && Math.abs(velocityY) > mMinFlingVelocity) {
- if (isDismissable()
- && velocityY < 0 && mCollapseOffset > mCollapsibleHeight) {
- smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, velocityY);
- mDismissOnScrollerFinished = true;
+ if (getShowAtTop()) {
+ if (isDismissable() && velocityY > 0) {
+ abortAnimation();
+ dismiss();
+ } else {
+ smoothScrollTo(velocityY < 0 ? mCollapsibleHeight : 0, velocityY);
+ }
} else {
- smoothScrollTo(velocityY > 0 ? 0 : mCollapsibleHeight, velocityY);
+ if (isDismissable()
+ && velocityY < 0 && mCollapseOffset > mCollapsibleHeight) {
+ smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, velocityY);
+ mDismissOnScrollerFinished = true;
+ } else {
+ smoothScrollTo(velocityY > 0 ? 0 : mCollapsibleHeight, velocityY);
+ }
}
return true;
}
@@ -794,7 +838,11 @@
updateCollapseOffset(oldCollapsibleHeight, !isDragging());
- mTopOffset = Math.max(0, heightSize - heightUsed) + (int) mCollapseOffset;
+ if (getShowAtTop()) {
+ mTopOffset = 0;
+ } else {
+ mTopOffset = Math.max(0, heightSize - heightUsed) + (int) mCollapseOffset;
+ }
setMeasuredDimension(sourceWidth, heightSize);
}
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index b5031f2..b7a6719 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -146,6 +146,9 @@
final ArrayMap<String, ArraySet<String>> mPrivAppPermissions = new ArrayMap<>();
final ArrayMap<String, ArraySet<String>> mPrivAppDenyPermissions = new ArrayMap<>();
+ final ArrayMap<String, ArraySet<String>> mVendorPrivAppPermissions = new ArrayMap<>();
+ final ArrayMap<String, ArraySet<String>> mVendorPrivAppDenyPermissions = new ArrayMap<>();
+
final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>();
public static SystemConfig getInstance() {
@@ -229,6 +232,14 @@
return mPrivAppDenyPermissions.get(packageName);
}
+ public ArraySet<String> getVendorPrivAppPermissions(String packageName) {
+ return mVendorPrivAppPermissions.get(packageName);
+ }
+
+ public ArraySet<String> getVendorPrivAppDenyPermissions(String packageName) {
+ return mVendorPrivAppDenyPermissions.get(packageName);
+ }
+
public Map<String, Boolean> getOemPermissions(String packageName) {
final Map<String, Boolean> oemPermissions = mOemPermissions.get(packageName);
if (oemPermissions != null) {
@@ -248,7 +259,7 @@
// Allow Vendor to customize system configs around libs, features, permissions and apps
int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
- ALLOW_APP_CONFIGS;
+ ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS;
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
readPermissions(Environment.buildPath(
@@ -587,7 +598,19 @@
}
XmlUtils.skipCurrentTag(parser);
} else if ("privapp-permissions".equals(name) && allowPrivappPermissions) {
- readPrivAppPermissions(parser);
+ // privapp permissions from system and vendor partitions are stored
+ // separately. This is to prevent xml files in the vendor partition from
+ // granting permissions to priv apps in the system partition and vice
+ // versa.
+ boolean vendor = permFile.toPath().startsWith(
+ Environment.getVendorDirectory().toPath());
+ if (vendor) {
+ readPrivAppPermissions(parser, mVendorPrivAppPermissions,
+ mVendorPrivAppDenyPermissions);
+ } else {
+ readPrivAppPermissions(parser, mPrivAppPermissions,
+ mPrivAppDenyPermissions);
+ }
} else if ("oem-permissions".equals(name) && allowOemPermissions) {
readOemPermissions(parser);
} else {
@@ -674,7 +697,10 @@
}
}
- void readPrivAppPermissions(XmlPullParser parser) throws IOException, XmlPullParserException {
+ private void readPrivAppPermissions(XmlPullParser parser,
+ ArrayMap<String, ArraySet<String>> grantMap,
+ ArrayMap<String, ArraySet<String>> denyMap)
+ throws IOException, XmlPullParserException {
String packageName = parser.getAttributeValue(null, "package");
if (TextUtils.isEmpty(packageName)) {
Slog.w(TAG, "package is required for <privapp-permissions> in "
@@ -682,11 +708,11 @@
return;
}
- ArraySet<String> permissions = mPrivAppPermissions.get(packageName);
+ ArraySet<String> permissions = grantMap.get(packageName);
if (permissions == null) {
permissions = new ArraySet<>();
}
- ArraySet<String> denyPermissions = mPrivAppDenyPermissions.get(packageName);
+ ArraySet<String> denyPermissions = denyMap.get(packageName);
int depth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, depth)) {
String name = parser.getName();
@@ -711,9 +737,9 @@
denyPermissions.add(permName);
}
}
- mPrivAppPermissions.put(packageName, permissions);
+ grantMap.put(packageName, permissions);
if (denyPermissions != null) {
- mPrivAppDenyPermissions.put(packageName, denyPermissions);
+ denyMap.put(packageName, denyPermissions);
}
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 961bcb9..8df0fb8 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -84,6 +84,7 @@
"android_view_VelocityTracker.cpp",
"android_text_AndroidCharacter.cpp",
"android_text_Hyphenator.cpp",
+ "android_text_MeasuredText.cpp",
"android_text_StaticLayout.cpp",
"android_os_Debug.cpp",
"android_os_GraphicsEnvironment.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f41aacd..9e907bd 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -177,6 +177,7 @@
extern int register_android_net_TrafficStats(JNIEnv* env);
extern int register_android_text_AndroidCharacter(JNIEnv *env);
extern int register_android_text_Hyphenator(JNIEnv *env);
+extern int register_android_text_MeasuredText(JNIEnv* env);
extern int register_android_text_StaticLayout(JNIEnv *env);
extern int register_android_opengl_classes(JNIEnv *env);
extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
@@ -1333,6 +1334,7 @@
REG_JNI(register_android_content_XmlBlock),
REG_JNI(register_android_text_AndroidCharacter),
REG_JNI(register_android_text_Hyphenator),
+ REG_JNI(register_android_text_MeasuredText),
REG_JNI(register_android_text_StaticLayout),
REG_JNI(register_android_view_InputDevice),
REG_JNI(register_android_view_KeyCharacterMap),
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 5990d7b..2e8c27a 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -130,8 +130,10 @@
chunk->paddingRight = int(chunk->paddingRight * scale + 0.5f);
chunk->paddingBottom = int(chunk->paddingBottom * scale + 0.5f);
- scaleDivRange(chunk->getXDivs(), chunk->numXDivs, scale, scaledWidth);
- scaleDivRange(chunk->getYDivs(), chunk->numYDivs, scale, scaledHeight);
+ // The max value for the divRange is one pixel less than the actual max to ensure that the size
+ // of the last div is not zero. A div of size 0 is considered invalid input and will not render.
+ scaleDivRange(chunk->getXDivs(), chunk->numXDivs, scale, scaledWidth - 1);
+ scaleDivRange(chunk->getYDivs(), chunk->numYDivs, scale, scaledHeight - 1);
}
class ScaleCheckingAllocator : public SkBitmap::HeapAllocator {
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.cpp b/core/jni/android/graphics/YuvToJpegEncoder.cpp
index 31567f7..5eecd9c 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.cpp
+++ b/core/jni/android/graphics/YuvToJpegEncoder.cpp
@@ -26,12 +26,13 @@
bool YuvToJpegEncoder::encode(SkWStream* stream, void* inYuv, int width,
int height, int* offsets, int jpegQuality) {
jpeg_compress_struct cinfo;
- skjpeg_error_mgr sk_err;
+ jpeg_error_mgr err;
skjpeg_destination_mgr sk_wstream(stream);
- cinfo.err = jpeg_std_error(&sk_err);
- sk_err.error_exit = skjpeg_error_exit;
- if (setjmp(sk_err.fJmpBuf)) {
+ cinfo.err = jpeg_std_error(&err);
+ err.error_exit = skjpeg_error_exit;
+ jmp_buf jmp;
+ if (setjmp(jmp)) {
return false;
}
jpeg_create_compress(&cinfo);
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index e9ea702..6f4a58a 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -96,6 +96,11 @@
tree->setAllowCaching(allowCaching);
}
+static void setAntiAlias(JNIEnv*, jobject, jlong treePtr, jboolean aa) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ tree->setAntiAlias(aa);
+}
+
/**
* Draw
*/
@@ -363,6 +368,7 @@
{"nSetRendererViewportSize", "(JFF)V", (void*)setTreeViewportSize},
{"nSetRootAlpha", "(JF)Z", (void*)setRootAlpha},
{"nGetRootAlpha", "(J)F", (void*)getRootAlpha},
+ {"nSetAntiAlias", "(JZ)V", (void*)setAntiAlias},
{"nSetAllowCaching", "(JZ)V", (void*)setAllowCaching},
{"nCreateFullPath", "()J", (void*)createEmptyFullPath},
diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp
index 6243fad..1eeea51 100644
--- a/core/jni/android_os_VintfObject.cpp
+++ b/core/jni/android_os_VintfObject.cpp
@@ -93,25 +93,33 @@
return toJavaStringArray(env, cStrings);
}
-static jint android_os_VintfObject_verify(JNIEnv* env, jclass, jobjectArray packageInfo) {
- size_t count = env->GetArrayLength(packageInfo);
- std::vector<std::string> cPackageInfo{count};
- for (size_t i = 0; i < count; ++i) {
- jstring element = (jstring)env->GetObjectArrayElement(packageInfo, i);
- const char *cString = env->GetStringUTFChars(element, NULL /* isCopy */);
- cPackageInfo[i] = cString;
- env->ReleaseStringUTFChars(element, cString);
+static jint verify(JNIEnv* env, jobjectArray packageInfo, android::vintf::DisabledChecks checks) {
+ std::vector<std::string> cPackageInfo;
+ if (packageInfo) {
+ size_t count = env->GetArrayLength(packageInfo);
+ cPackageInfo.resize(count);
+ for (size_t i = 0; i < count; ++i) {
+ jstring element = (jstring)env->GetObjectArrayElement(packageInfo, i);
+ const char *cString = env->GetStringUTFChars(element, NULL /* isCopy */);
+ cPackageInfo[i] = cString;
+ env->ReleaseStringUTFChars(element, cString);
+ }
}
- // If we can run this code, the device should already pass AVB.
- // So, we don't need to check AVB here.
std::string error;
- int32_t status = VintfObject::CheckCompatibility(
- cPackageInfo, &error, ::android::vintf::DISABLE_AVB_CHECK);
+ int32_t status = VintfObject::CheckCompatibility(cPackageInfo, &error, checks);
if (status)
LOG(WARNING) << "VintfObject.verify() returns " << status << ": " << error;
return status;
}
+static jint android_os_VintfObject_verify(JNIEnv* env, jclass, jobjectArray packageInfo) {
+ return verify(env, packageInfo, ::android::vintf::ENABLE_ALL_CHECKS);
+}
+
+static jint android_os_VintfObject_verifyWithoutAvb(JNIEnv* env, jclass) {
+ return verify(env, nullptr, ::android::vintf::DISABLE_AVB_CHECK);
+}
+
static jobjectArray android_os_VintfObject_getHalNamesAndVersions(JNIEnv* env, jclass) {
std::set<std::string> halNames;
tryAddHalNamesAndVersions(VintfObject::GetDeviceHalManifest(),
@@ -151,6 +159,7 @@
static const JNINativeMethod gVintfObjectMethods[] = {
{"report", "()[Ljava/lang/String;", (void*)android_os_VintfObject_report},
{"verify", "([Ljava/lang/String;)I", (void*)android_os_VintfObject_verify},
+ {"verifyWithoutAvb", "()I", (void*)android_os_VintfObject_verifyWithoutAvb},
{"getHalNamesAndVersions", "()[Ljava/lang/String;", (void*)android_os_VintfObject_getHalNamesAndVersions},
{"getSepolicyVersion", "()Ljava/lang/String;", (void*)android_os_VintfObject_getSepolicyVersion},
{"getVndkSnapshots", "()Ljava/util/Map;", (void*)android_os_VintfObject_getVndkSnapshots},
diff --git a/core/jni/android_text_MeasuredText.cpp b/core/jni/android_text_MeasuredText.cpp
new file mode 100644
index 0000000..af9d131
--- /dev/null
+++ b/core/jni/android_text_MeasuredText.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "MeasuredText"
+
+#include "ScopedIcuLocale.h"
+#include "unicode/locid.h"
+#include "unicode/brkiter.h"
+#include "utils/misc.h"
+#include "utils/Log.h"
+#include <nativehelper/ScopedStringChars.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/JNIHelp.h>
+#include "core_jni_helpers.h"
+#include <cstdint>
+#include <vector>
+#include <list>
+#include <algorithm>
+
+#include "SkPaint.h"
+#include "SkTypeface.h"
+#include <hwui/MinikinSkia.h>
+#include <hwui/MinikinUtils.h>
+#include <hwui/Paint.h>
+#include <minikin/FontCollection.h>
+#include <minikin/AndroidLineBreakerHelper.h>
+#include <minikin/MinikinFont.h>
+
+namespace android {
+
+static inline minikin::MeasuredTextBuilder* toBuilder(jlong ptr) {
+ return reinterpret_cast<minikin::MeasuredTextBuilder*>(ptr);
+}
+
+static inline Paint* toPaint(jlong ptr) {
+ return reinterpret_cast<Paint*>(ptr);
+}
+
+static inline minikin::MeasuredText* toMeasuredText(jlong ptr) {
+ return reinterpret_cast<minikin::MeasuredText*>(ptr);
+}
+
+template<typename Ptr> static inline jlong toJLong(Ptr ptr) {
+ return reinterpret_cast<jlong>(ptr);
+}
+
+static void releaseMeasuredText(jlong measuredTextPtr) {
+ delete toMeasuredText(measuredTextPtr);
+}
+
+// Regular JNI
+static jlong nInitBuilder() {
+ return toJLong(new minikin::MeasuredTextBuilder());
+}
+
+// Regular JNI
+static void nAddStyleRun(JNIEnv* /* unused */, jclass /* unused */, jlong builderPtr,
+ jlong paintPtr, jint start, jint end, jboolean isRtl) {
+ Paint* paint = toPaint(paintPtr);
+ const Typeface* typeface = Typeface::resolveDefault(paint->getAndroidTypeface());
+ minikin::MinikinPaint minikinPaint = MinikinUtils::prepareMinikinPaint(paint, typeface);
+ toBuilder(builderPtr)->addStyleRun(start, end, std::move(minikinPaint),
+ typeface->fFontCollection, isRtl);
+}
+
+// Regular JNI
+static void nAddReplacementRun(JNIEnv* /* unused */, jclass /* unused */, jlong builderPtr,
+ jlong paintPtr, jint start, jint end, jfloat width) {
+ toBuilder(builderPtr)->addReplacementRun(start, end, width,
+ toPaint(paintPtr)->getMinikinLocaleListId());
+}
+
+// Regular JNI
+static jlong nBuildNativeMeasuredText(JNIEnv* env, jclass /* unused */, jlong builderPtr,
+ jcharArray javaText) {
+ ScopedCharArrayRO text(env, javaText);
+ const minikin::U16StringPiece textBuffer(text.get(), text.size());
+
+ // Pass the ownership to Java.
+ return toJLong(toBuilder(builderPtr)->build(textBuffer).release());
+}
+
+// Regular JNI
+static void nFreeBuilder(JNIEnv* env, jclass /* unused */, jlong builderPtr) {
+ delete toBuilder(builderPtr);
+}
+
+// CriticalNative
+static jlong nGetReleaseFunc() {
+ return toJLong(&releaseMeasuredText);
+}
+
+static const JNINativeMethod gMethods[] = {
+ // MeasuredTextBuilder native functions.
+ {"nInitBuilder", "()J", (void*) nInitBuilder},
+ {"nAddStyleRun", "(JJIIZ)V", (void*) nAddStyleRun},
+ {"nAddReplacementRun", "(JJIIF)V", (void*) nAddReplacementRun},
+ {"nBuildNativeMeasuredText", "(J[C)J", (void*) nBuildNativeMeasuredText},
+ {"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
+
+ // MeasuredText native functions.
+ {"nGetReleaseFunc", "()J", (void*) nGetReleaseFunc}, // Critical Natives
+};
+
+int register_android_text_MeasuredText(JNIEnv* env) {
+ return RegisterMethodsOrDie(env, "android/text/MeasuredText", gMethods, NELEM(gMethods));
+}
+
+}
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index d7300c4..b5c23df 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -25,6 +25,7 @@
#include <nativehelper/ScopedPrimitiveArray.h>
#include <nativehelper/JNIHelp.h>
#include "core_jni_helpers.h"
+#include "scoped_nullable_primitive_array.h"
#include <cstdint>
#include <vector>
#include <list>
@@ -87,9 +88,8 @@
static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
jfloatArray recycleWidths, jfloatArray recycleAscents,
jfloatArray recycleDescents, jintArray recycleFlags,
- jint recycleLength, size_t nBreaks, const jint* breaks,
- const jfloat* widths, const jfloat* ascents, const jfloat* descents,
- const jint* flags) {
+ jint recycleLength, const minikin::LineBreakResult& result) {
+ const size_t nBreaks = result.breakPoints.size();
if ((size_t)recycleLength < nBreaks) {
// have to reallocate buffers
recycleBreaks = env->NewIntArray(nBreaks);
@@ -105,16 +105,17 @@
env->SetObjectField(recycle, gLineBreaks_fieldID.flags, recycleFlags);
}
// copy data
- env->SetIntArrayRegion(recycleBreaks, 0, nBreaks, breaks);
- env->SetFloatArrayRegion(recycleWidths, 0, nBreaks, widths);
- env->SetFloatArrayRegion(recycleAscents, 0, nBreaks, ascents);
- env->SetFloatArrayRegion(recycleDescents, 0, nBreaks, descents);
- env->SetIntArrayRegion(recycleFlags, 0, nBreaks, flags);
+ env->SetIntArrayRegion(recycleBreaks, 0, nBreaks, result.breakPoints.data());
+ env->SetFloatArrayRegion(recycleWidths, 0, nBreaks, result.widths.data());
+ env->SetFloatArrayRegion(recycleAscents, 0, nBreaks, result.ascents.data());
+ env->SetFloatArrayRegion(recycleDescents, 0, nBreaks, result.descents.data());
+ env->SetIntArrayRegion(recycleFlags, 0, nBreaks, result.flags.data());
}
static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
// Inputs
jcharArray javaText,
+ jlong measuredTextPtr,
jint length,
jfloat firstWidth,
jint firstWidthLineCount,
@@ -136,52 +137,21 @@
minikin::android::StaticLayoutNative* builder = toNative(nativePtr);
ScopedCharArrayRO text(env, javaText);
+ ScopedNullableIntArrayRO tabStops(env, variableTabStops);
- // TODO: Reorganize minikin APIs.
- minikin::LineBreaker b(minikin::U16StringPiece(text.get(), length));
- if (variableTabStops == nullptr) {
- b.setTabStops(nullptr, 0, defaultTabStop);
- } else {
- ScopedIntArrayRO stops(env, variableTabStops);
- b.setTabStops(stops.get(), stops.size(), defaultTabStop);
- }
- b.setStrategy(builder->getStrategy());
- b.setHyphenationFrequency(builder->getFrequency());
- b.setJustified(builder->isJustified());
- b.setLineWidthDelegate(builder->buildLineWidthDelegate(
- firstWidth, firstWidthLineCount, restWidth, indentsOffset));
-
- builder->addRuns(&b);
-
- size_t nBreaks = b.computeBreaks();
+ minikin::U16StringPiece u16Text(text.get(), length);
+ minikin::MeasuredText* measuredText = reinterpret_cast<minikin::MeasuredText*>(measuredTextPtr);
+ minikin::LineBreakResult result = builder->computeBreaks(
+ u16Text, *measuredText, firstWidth, firstWidthLineCount, restWidth, indentsOffset,
+ tabStops.get(), tabStops.size(), defaultTabStop);
recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleAscents, recycleDescents,
- recycleFlags, recycleLength, nBreaks, b.getBreaks(), b.getWidths(), b.getAscents(),
- b.getDescents(), b.getFlags());
+ recycleFlags, recycleLength, result);
- env->SetFloatArrayRegion(charWidths, 0, b.size(), b.charWidths());
+ env->SetFloatArrayRegion(charWidths, 0, measuredText->widths.size(),
+ measuredText->widths.data());
- builder->clearRuns();
-
- return static_cast<jint>(nBreaks);
-}
-
-// Basically similar to Paint.getTextRunAdvances but with C++ interface
-// CriticalNative
-static void nAddStyleRun(jlong nativePtr, jlong nativePaint, jint start, jint end, jboolean isRtl) {
- minikin::android::StaticLayoutNative* builder = toNative(nativePtr);
- Paint* paint = reinterpret_cast<Paint*>(nativePaint);
- const Typeface* typeface = Typeface::resolveDefault(paint->getAndroidTypeface());
- minikin::MinikinPaint minikinPaint = MinikinUtils::prepareMinikinPaint(paint, typeface);
- builder->addStyleRun(start, end, std::move(minikinPaint), typeface->fFontCollection, isRtl);
-}
-
-// CriticalNative
-static void nAddReplacementRun(jlong nativePtr, jlong nativePaint, jint start, jint end,
- jfloat width) {
- minikin::android::StaticLayoutNative* builder = toNative(nativePtr);
- Paint* paint = reinterpret_cast<Paint*>(nativePaint);
- builder->addReplacementRun(start, end, width, paint->getMinikinLocaleListId());
+ return static_cast<jint>(result.breakPoints.size());
}
static const JNINativeMethod gMethods[] = {
@@ -197,8 +167,6 @@
// Critical Natives
{"nFinish", "(J)V", (void*) nFinish},
- {"nAddStyleRun", "(JJIIZ)V", (void*) nAddStyleRun},
- {"nAddReplacementRun", "(JJIIF)V", (void*) nAddReplacementRun},
// Regular JNI
{"nComputeLineBreaks", "("
@@ -206,6 +174,7 @@
// Inputs
"[C" // text
+ "J" // MeasuredText ptr.
"I" // length
"F" // firstWidth
"I" // firstWidthLineCount
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index 71742cb..0a90b97 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -124,7 +124,7 @@
static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
jclass clazz, jstring nameObj) {
const char* nameChars = env->GetStringUTFChars(nameObj, NULL);
- String8 name(nameChars);
+ std::string name = nameChars;
env->ReleaseStringUTFChars(nameObj, nameChars);
sp<InputChannel> serverChannel;
@@ -166,7 +166,7 @@
if (nativeInputChannel) {
if (finalized) {
ALOGW("Input channel object '%s' was finalized without being disposed!",
- nativeInputChannel->getInputChannel()->getName().string());
+ nativeInputChannel->getInputChannel()->getName().c_str());
}
nativeInputChannel->invokeAndRemoveDisposeCallback(env, obj);
@@ -212,7 +212,7 @@
return;
}
- InputChannel* inputChannel = new InputChannel(name, dupFd);
+ InputChannel* inputChannel = new InputChannel(name.string(), dupFd);
NativeInputChannel* nativeInputChannel = new NativeInputChannel(inputChannel);
android_view_InputChannel_setNativeInputChannel(env, obj, nativeInputChannel);
@@ -230,7 +230,7 @@
sp<InputChannel> inputChannel = nativeInputChannel->getInputChannel();
parcel->writeInt32(1);
- parcel->writeString8(inputChannel->getName());
+ parcel->writeString8(String8(inputChannel->getName().c_str()));
parcel->writeDupFileDescriptor(inputChannel->getFd());
} else {
parcel->writeInt32(0);
@@ -245,7 +245,7 @@
return NULL;
}
- jstring name = env->NewStringUTF(nativeInputChannel->getInputChannel()->getName().string());
+ jstring name = env->NewStringUTF(nativeInputChannel->getInputChannel()->getName().c_str());
return name;
}
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index c457ab0..52c84a4 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -79,7 +79,7 @@
void setFdEvents(int events);
const char* getInputChannelName() {
- return mInputConsumer.getChannel()->getName().string();
+ return mInputConsumer.getChannel()->getName().c_str();
}
virtual int handleEvent(int receiveFd, int events, void* data);
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index 58ccef18..f87abac 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -71,7 +71,7 @@
uint32_t mNextPublishedSeq;
const char* getInputChannelName() {
- return mInputPublisher.getChannel()->getName().string();
+ return mInputPublisher.getChannel()->getName().c_str();
}
virtual int handleEvent(int receiveFd, int events, void* data);
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 3ad4da6..421e0de 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -517,23 +517,7 @@
jobject graphicBuffer) {
Surface* surface = reinterpret_cast<Surface*>(nativeObject);
sp<GraphicBuffer> bp = graphicBufferForJavaObject(env, graphicBuffer);
- if (bp == nullptr) {
- return BAD_VALUE;
- }
- int err = ((ANativeWindow*)surface)->perform(surface, NATIVE_WINDOW_API_CONNECT,
- NATIVE_WINDOW_API_CPU);
- if (err != OK) {
- return err;
- }
- err = surface->attachBuffer(bp->getNativeBuffer());
- if (err != OK) {
- return err;
- }
- err = ((ANativeWindow*)surface)->queueBuffer(surface, bp->getNativeBuffer(), -1);
- if (err != OK) {
- return err;
- }
- err = surface->disconnect(NATIVE_WINDOW_API_CPU);
+ int err = Surface::attachAndQueueBuffer(surface, bp);
return err;
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index bb1bfad..5e5d59b 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -167,7 +167,7 @@
maxLayer = INT32_MAX;
}
sp<GraphicBuffer> buffer;
- status_t res = ScreenshotClient::captureToBuffer(displayToken,
+ status_t res = ScreenshotClient::capture(displayToken,
sourceCrop, width, height, minLayer, maxLayer, useIdentityTransform,
rotation, &buffer);
if (res != NO_ERROR) {
@@ -201,15 +201,18 @@
maxLayer = INT32_MAX;
}
- res = screenshot->update(displayToken, sourceCrop, width, height,
- minLayer, maxLayer, useIdentityTransform, static_cast<uint32_t>(rotation));
+ sp<GraphicBuffer> buffer;
+ res = ScreenshotClient::capture(displayToken, sourceCrop, width, height,
+ minLayer, maxLayer, useIdentityTransform, static_cast<uint32_t>(rotation), &buffer);
if (res != NO_ERROR) {
return NULL;
}
SkColorType colorType;
SkAlphaType alphaType;
- switch (screenshot->getFormat()) {
+
+ PixelFormat format = buffer->getPixelFormat();
+ switch (format) {
case PIXEL_FORMAT_RGBX_8888: {
colorType = kRGBA_8888_SkColorType;
alphaType = kOpaque_SkAlphaType;
@@ -235,66 +238,20 @@
}
}
- sk_sp<SkColorSpace> colorSpace;
- if (screenshot->getDataSpace() == HAL_DATASPACE_DISPLAY_P3) {
- colorSpace = SkColorSpace::MakeRGB(
- SkColorSpace::kSRGB_RenderTargetGamma, SkColorSpace::kDCIP3_D65_Gamut);
- } else {
- colorSpace = SkColorSpace::MakeSRGB();
- }
+ SkImageInfo info = SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(),
+ colorType, alphaType,
+ SkColorSpace::MakeSRGB());
- SkImageInfo screenshotInfo = SkImageInfo::Make(screenshot->getWidth(),
- screenshot->getHeight(),
- colorType,
- alphaType,
- colorSpace);
-
- const size_t rowBytes =
- screenshot->getStride() * android::bytesPerPixel(screenshot->getFormat());
-
- if (!screenshotInfo.width() || !screenshotInfo.height()) {
- return NULL;
- }
-
- auto bitmap = new Bitmap(
- (void*) screenshot->getPixels(), (void*) screenshot.get(), DeleteScreenshot,
- screenshotInfo, rowBytes);
- screenshot.release();
- bitmap->setImmutable();
- return bitmap::createBitmap(env, bitmap,
- android::bitmap::kBitmapCreateFlag_Premultiplied, NULL);
+ auto bitmap = sk_sp<Bitmap>(new Bitmap(buffer.get(), info));
+ return bitmap::createBitmap(env, bitmap.release(),
+ android::bitmap::kBitmapCreateFlag_Premultiplied, NULL);
}
static void nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj,
jobject surfaceObj, jobject sourceCropObj, jint width, jint height,
jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform) {
sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
- if (displayToken != NULL) {
- sp<Surface> consumer = android_view_Surface_getSurface(env, surfaceObj);
- if (consumer != NULL) {
- int left = env->GetIntField(sourceCropObj, gRectClassInfo.left);
- int top = env->GetIntField(sourceCropObj, gRectClassInfo.top);
- int right = env->GetIntField(sourceCropObj, gRectClassInfo.right);
- int bottom = env->GetIntField(sourceCropObj, gRectClassInfo.bottom);
- Rect sourceCrop(left, top, right, bottom);
-
- if (allLayers) {
- minLayer = INT32_MIN;
- maxLayer = INT32_MAX;
- }
- ScreenshotClient::capture(displayToken,
- consumer->getIGraphicBufferProducer(), sourceCrop,
- width, height, minLayer, maxLayer,
- useIdentityTransform);
- }
- }
-}
-
-static void nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandleToken,
- jobject surfaceObj, int rotation) {
-
- sp<IBinder> layerHandle = ibinderForJavaObject(env, layerHandleToken);
- if (layerHandle == NULL) {
+ if (displayToken == NULL) {
return;
}
@@ -303,7 +260,49 @@
return;
}
- ScreenshotClient::captureLayers(layerHandle, consumer->getIGraphicBufferProducer(), rotation);
+ Rect sourceCrop;
+ if (sourceCropObj != NULL) {
+ sourceCrop = rectFromObj(env, sourceCropObj);
+ }
+
+ if (allLayers) {
+ minLayer = INT32_MIN;
+ maxLayer = INT32_MAX;
+ }
+
+ sp<GraphicBuffer> buffer;
+ ScreenshotClient::capture(displayToken, sourceCrop, width, height, minLayer, maxLayer,
+ useIdentityTransform, 0, &buffer);
+
+ Surface::attachAndQueueBuffer(consumer.get(), buffer);
+}
+
+static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandleToken,
+ jobject sourceCropObj, jfloat frameScale) {
+
+ sp<IBinder> layerHandle = ibinderForJavaObject(env, layerHandleToken);
+ if (layerHandle == NULL) {
+ return NULL;
+ }
+
+ Rect sourceCrop;
+ if (sourceCropObj != NULL) {
+ sourceCrop = rectFromObj(env, sourceCropObj);
+ }
+
+ sp<GraphicBuffer> buffer;
+ status_t res = ScreenshotClient::captureLayers(layerHandle, sourceCrop, frameScale, &buffer);
+ if (res != NO_ERROR) {
+ return NULL;
+ }
+
+ return env->CallStaticObjectMethod(gGraphicBufferClassInfo.clazz,
+ gGraphicBufferClassInfo.builder,
+ buffer->getWidth(),
+ buffer->getHeight(),
+ buffer->getPixelFormat(),
+ (jint)buffer->getUsage(),
+ (jlong)buffer.get());
}
static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync) {
@@ -869,11 +868,40 @@
capabilities.getDesiredMaxAverageLuminance(), capabilities.getDesiredMinLuminance());
}
+static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj) {
+ Parcel* parcel = parcelForJavaObject(env, parcelObj);
+ if (parcel == NULL) {
+ doThrowNPE(env);
+ return 0;
+ }
+ sp<SurfaceControl> surface = SurfaceControl::readFromParcel(parcel);
+ if (surface == nullptr) {
+ return 0;
+ }
+ surface->incStrong((void *)nativeCreate);
+ return reinterpret_cast<jlong>(surface.get());
+}
+
+static void nativeWriteToParcel(JNIEnv* env, jclass clazz,
+ jlong nativeObject, jobject parcelObj) {
+ Parcel* parcel = parcelForJavaObject(env, parcelObj);
+ if (parcel == NULL) {
+ doThrowNPE(env);
+ return;
+ }
+ SurfaceControl* const self = reinterpret_cast<SurfaceControl *>(nativeObject);
+ self->writeToParcel(parcel);
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod sSurfaceControlMethods[] = {
{"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIIIJII)J",
(void*)nativeCreate },
+ {"nativeReadFromParcel", "(Landroid/os/Parcel;)J",
+ (void*)nativeReadFromParcel },
+ {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V",
+ (void*)nativeWriteToParcel },
{"nativeRelease", "(J)V",
(void*)nativeRelease },
{"nativeDestroy", "(J)V",
@@ -975,7 +1003,7 @@
{"nativeScreenshotToBuffer",
"(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/GraphicBuffer;",
(void*)nativeScreenshotToBuffer },
- {"nativeCaptureLayers", "(Landroid/os/IBinder;Landroid/view/Surface;I)V",
+ {"nativeCaptureLayers", "(Landroid/os/IBinder;Landroid/graphics/Rect;F)Landroid/graphics/GraphicBuffer;",
(void*)nativeCaptureLayers },
};
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 870a0c2..9f3475a 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -937,6 +937,11 @@
Properties::enableHighContrastText = enable;
}
+static void android_view_ThreadedRenderer_hackySetRTAnimationsEnabled(JNIEnv*, jclass,
+ jboolean enable) {
+ Properties::enableRTAnimations = enable;
+}
+
// ----------------------------------------------------------------------------
// FrameMetricsObserver
// ----------------------------------------------------------------------------
@@ -1041,9 +1046,26 @@
(void*)android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode },
{ "disableVsync", "()V", (void*)android_view_ThreadedRenderer_disableVsync },
{ "nSetHighContrastText", "(Z)V", (void*)android_view_ThreadedRenderer_setHighContrastText },
+ { "nHackySetRTAnimationsEnabled", "(Z)V",
+ (void*)android_view_ThreadedRenderer_hackySetRTAnimationsEnabled },
};
+static JavaVM* mJvm = nullptr;
+
+static void attachRenderThreadToJvm() {
+ LOG_ALWAYS_FATAL_IF(!mJvm, "No jvm but we set the hook??");
+
+ JavaVMAttachArgs args;
+ args.version = JNI_VERSION_1_4;
+ args.name = (char*) "RenderThread";
+ args.group = NULL;
+ JNIEnv* env;
+ mJvm->AttachCurrentThreadAsDaemon(&env, (void*) &args);
+}
+
int register_android_view_ThreadedRenderer(JNIEnv* env) {
+ env->GetJavaVM(&mJvm);
+ RenderThread::setOnStartHook(&attachRenderThreadToJvm);
jclass observerClass = FindClassOrDie(env, "android/view/FrameMetricsObserver");
gFrameMetricsObserverClassInfo.frameMetrics = GetFieldIDOrDie(
env, observerClass, "mFrameMetrics", "Landroid/view/FrameMetrics;");
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 32ef3dc..1407ae4 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -776,7 +776,10 @@
}
// Assign system_server to the correct memory cgroup.
- if (!WriteStringToFile(StringPrintf("%d", pid), "/dev/memcg/system/tasks")) {
+ // Not all devices mount /dev/memcg so check for the file first
+ // to avoid unnecessarily printing errors and denials in the logs.
+ if (!access("/dev/memcg/system/tasks", F_OK) &&
+ !WriteStringToFile(StringPrintf("%d", pid), "/dev/memcg/system/tasks")) {
ALOGE("couldn't write %d to /dev/memcg/system/tasks", pid);
}
}
diff --git a/core/jni/scoped_nullable_primitive_array.h b/core/jni/scoped_nullable_primitive_array.h
new file mode 100644
index 0000000..77f4c9d
--- /dev/null
+++ b/core/jni/scoped_nullable_primitive_array.h
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+#ifndef SCOPED_NULLABLE_PRIMITIVE_ARRAY_H
+#define SCOPED_NULLABLE_PRIMITIVE_ARRAY_H
+
+#include <jni.h>
+
+namespace android {
+
+#define ARRAY_TRAITS(ARRAY_TYPE, POINTER_TYPE, NAME) \
+class NAME ## ArrayTraits { \
+public: \
+ static constexpr void getArrayRegion(JNIEnv* env, ARRAY_TYPE array, size_t start, \
+ size_t len, POINTER_TYPE out) { \
+ env->Get ## NAME ## ArrayRegion(array, start, len, out); \
+ } \
+ \
+ static constexpr POINTER_TYPE getArrayElements(JNIEnv* env, ARRAY_TYPE array) { \
+ return env->Get ## NAME ## ArrayElements(array, nullptr); \
+ } \
+ \
+ static constexpr void releaseArrayElements(JNIEnv* env, ARRAY_TYPE array, \
+ POINTER_TYPE buffer, jint mode) { \
+ env->Release ## NAME ## ArrayElements(array, buffer, mode); \
+ } \
+}; \
+
+ARRAY_TRAITS(jbooleanArray, jboolean*, Boolean)
+ARRAY_TRAITS(jbyteArray, jbyte*, Byte)
+ARRAY_TRAITS(jcharArray, jchar*, Char)
+ARRAY_TRAITS(jdoubleArray, jdouble*, Double)
+ARRAY_TRAITS(jfloatArray, jfloat*, Float)
+ARRAY_TRAITS(jintArray, jint*, Int)
+ARRAY_TRAITS(jlongArray, jlong*, Long)
+ARRAY_TRAITS(jshortArray, jshort*, Short)
+
+#undef ARRAY_TRAITS
+
+template<typename JavaArrayType, typename PrimitiveType, class Traits, size_t preallocSize = 10>
+class ScopedArrayRO {
+public:
+ ScopedArrayRO(JNIEnv* env, JavaArrayType javaArray) : mEnv(env), mJavaArray(javaArray) {
+ if (mJavaArray == nullptr) {
+ mSize = 0;
+ mRawArray = nullptr;
+ } else {
+ mSize = mEnv->GetArrayLength(mJavaArray);
+ if (mSize <= preallocSize) {
+ Traits::getArrayRegion(mEnv, mJavaArray, 0, mSize, mBuffer);
+ mRawArray = mBuffer;
+ } else {
+ mRawArray = Traits::getArrayElements(mEnv, mJavaArray);
+ }
+ }
+ }
+
+ ~ScopedArrayRO() {
+ if (mRawArray != nullptr && mRawArray != mBuffer) {
+ Traits::releaseArrayElements(mEnv, mJavaArray, mRawArray, JNI_ABORT);
+ }
+ }
+
+ const PrimitiveType* get() const { return mRawArray; }
+ const PrimitiveType& operator[](size_t n) const { return mRawArray[n]; }
+ size_t size() const { return mSize; }
+
+private:
+ JNIEnv* const mEnv;
+ JavaArrayType mJavaArray;
+ PrimitiveType* mRawArray;
+ size_t mSize;
+ PrimitiveType mBuffer[preallocSize];
+ DISALLOW_COPY_AND_ASSIGN(ScopedArrayRO);
+};
+
+// ScopedNullable***ArrayRO provide convenient read-only access to Java array from JNI code.
+// These accept nullptr. In that case, get() returns nullptr and size() returns 0.
+using ScopedNullableBooleanArrayRO = ScopedArrayRO<jbooleanArray, jboolean, BooleanArrayTraits>;
+using ScopedNullableByteArrayRO = ScopedArrayRO<jbyteArray, jbyte, ByteArrayTraits>;
+using ScopedNullableCharArrayRO = ScopedArrayRO<jcharArray, jchar, CharArrayTraits>;
+using ScopedNullableDoubleArrayRO = ScopedArrayRO<jdoubleArray, jdouble, DoubleArrayTraits>;
+using ScopedNullableFloatArrayRO = ScopedArrayRO<jfloatArray, jfloat, FloatArrayTraits>;
+using ScopedNullableIntArrayRO = ScopedArrayRO<jintArray, jint, IntArrayTraits>;
+using ScopedNullableLongArrayRO = ScopedArrayRO<jlongArray, jlong, LongArrayTraits>;
+using ScopedNullableShortArrayRO = ScopedArrayRO<jshortArray, jshort, ShortArrayTraits>;
+
+} // namespace android
+
+#endif // SCOPED_NULLABLE_PRIMITIVE_ARRAY_H
diff --git a/core/proto/android/os/batterystats.proto b/core/proto/android/os/batterystats.proto
index 0a3344f..cff1879 100644
--- a/core/proto/android/os/batterystats.proto
+++ b/core/proto/android/os/batterystats.proto
@@ -395,6 +395,12 @@
};
repeated WakeupReason wakeup_reason = 22;
+ message WifiMulticastWakelockTotal {
+ optional int64 duration_ms = 1;
+ optional int32 count = 2;
+ }
+ optional WifiMulticastWakelockTotal wifi_multicast_wakelock_total = 23;
+
message WifiSignalStrength {
enum Name {
NONE = 0;
@@ -406,7 +412,7 @@
optional Name name = 1;
optional TimerProto total = 2;
};
- repeated WifiSignalStrength wifi_signal_strength = 23;
+ repeated WifiSignalStrength wifi_signal_strength = 24;
message WifiState {
enum Name {
@@ -422,7 +428,7 @@
optional Name name = 1;
optional TimerProto total = 2;
};
- repeated WifiState wifi_state = 24;
+ repeated WifiState wifi_state = 25;
message WifiSupplicantState {
enum Name {
@@ -443,7 +449,7 @@
optional Name name = 1;
optional TimerProto total = 2;
};
- repeated WifiSupplicantState wifi_supplicant_state = 25;
+ repeated WifiSupplicantState wifi_supplicant_state = 26;
}
message TimerProto {
@@ -775,4 +781,12 @@
optional TimerProto background_scan = 4;
};
optional Wifi wifi = 27;
+
+ // WiFi Multicast Wakelock
+ // This timer tracks the duration and count for the app to request the
+ // wakelock for wifi multicast traffic.
+ // This wakelock disables the filtering of multicast packets to reach the host
+ // processor, and results in a power penalty.
+ // It is useful to monitor the applications resulting in that
+ optional TimerProto wifi_multicast_wakelock = 28;
}
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index ecdabcf..8ed958d 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -18,8 +18,6 @@
option java_multiple_files = true;
option java_outer_classname = "IncidentProtoMetadata";
-import "frameworks/base/libs/incident/proto/android/privacy.proto";
-import "frameworks/base/libs/incident/proto/android/section.proto";
import "frameworks/base/core/proto/android/os/cpufreq.proto";
import "frameworks/base/core/proto/android/os/cpuinfo.proto";
import "frameworks/base/core/proto/android/os/incidentheader.proto";
@@ -42,6 +40,8 @@
import "frameworks/base/core/proto/android/service/package.proto";
import "frameworks/base/core/proto/android/service/print.proto";
import "frameworks/base/core/proto/android/service/procstats.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+import "frameworks/base/libs/incident/proto/android/section.proto";
package android.os;
@@ -164,4 +164,9 @@
(section).type = SECTION_DUMPSYS,
(section).args = "window --proto"
];
+
+ optional com.android.server.am.proto.MemInfoProto meminfo = 3018 [
+ (section).type = SECTION_DUMPSYS,
+ (section).args = "meminfo --proto"
+ ];
}
diff --git a/core/proto/android/os/procrank.proto b/core/proto/android/os/procrank.proto
index 9945f2e..f684c84 100644
--- a/core/proto/android/os/procrank.proto
+++ b/core/proto/android/os/procrank.proto
@@ -18,12 +18,15 @@
option java_multiple_files = true;
option java_outer_classname = "ProcrankProto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
import "frameworks/base/tools/streaming_proto/stream.proto";
package android.os;
//Memory usage of running processes
message Procrank {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
// Currently running process
repeated ProcessProto processes = 1;
@@ -34,6 +37,7 @@
// Next Tag: 11
message ProcessProto {
option (stream_proto.stream_msg).enable_fields_mapping = true;
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
// ID of the process
optional int32 pid = 1;
@@ -68,6 +72,8 @@
// Next Tag: 3
message SummaryProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional ProcessProto total = 1;
optional ZramProto zram = 2;
@@ -77,9 +83,13 @@
// TODO: sync on how to use these values
message ZramProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string raw_text = 1;
}
message RamProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string raw_text = 1;
}
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index 5d5aea2..8d091ab 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -281,6 +281,7 @@
optional SettingProto bluetooth_pbap_client_priority_prefix = 209;
optional SettingProto bluetooth_sap_priority_prefix = 210;
optional SettingProto bluetooth_pan_priority_prefix = 211;
+ optional SettingProto bluetooth_hearing_aid_priority_prefix = 345;
optional SettingProto activity_manager_constants = 317;
optional SettingProto device_idle_constants = 212;
optional SettingProto device_idle_constants_watch = 213;
@@ -366,7 +367,7 @@
optional SettingProto database_creation_buildid = 330;
optional SettingProto contacts_database_wal_enabled = 275;
optional SettingProto location_settings_link_to_permissions_enabled = 331;
- optional SettingProto backup_refactored_service_disabled = 332;
+ reserved 332; // Removed backup_refactored_service_disabled
optional SettingProto euicc_factory_reset_timeout_millis = 333;
optional SettingProto storage_settings_clobber_threshold = 334;
optional SettingProto multi_sim_voice_call_subscription = 276;
@@ -387,7 +388,7 @@
optional SettingProto enable_deletion_helper_no_threshold_toggle = 340;
optional SettingProto notification_snooze_options = 341;
- // Next tag = 345;
+ // Next tag = 346;
}
message SecureSettingsProto {
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 889842c..3af6f51 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -16,16 +16,16 @@
syntax = "proto2";
+package com.android.server.am.proto;
+
import "frameworks/base/core/proto/android/app/notification.proto";
import "frameworks/base/core/proto/android/content/intent.proto";
-import "frameworks/base/core/proto/android/server/intentresolver.proto";
-import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
import "frameworks/base/core/proto/android/graphics/rect.proto";
import "frameworks/base/core/proto/android/os/looper.proto";
+import "frameworks/base/core/proto/android/server/intentresolver.proto";
+import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
import "frameworks/base/core/proto/android/util/common.proto";
-package com.android.server.am.proto;
-
option java_multiple_files = true;
message ActivityManagerServiceProto {
@@ -159,6 +159,69 @@
repeated BroadcastSummary historical_broadcasts_summary = 6;
}
+message MemInfoProto {
+ optional int64 uptime_duration_ms = 1;
+ optional int64 elapsed_realtime_ms = 2;
+
+ message NativeProcess {
+ optional int32 pid = 1;
+ optional string process_name = 2;
+
+ message MemoryInfo {
+ optional string name = 1;
+ // The proportional set size for the heap.
+ optional int32 total_pss_kb = 2;
+ // The proportional set size that is swappable for the heap.
+ optional int32 clean_pss_kb = 3;
+ // The private dirty pages used by the heap.
+ optional int32 shared_dirty_kb = 4;
+ // The shared dirty pages used by the heap.
+ optional int32 private_dirty_kb = 5;
+ // The shared clean pages used by the heap.
+ optional int32 shared_clean_kb = 6;
+ // The private clean pages used by the heap.
+ optional int32 private_clean_kb = 7;
+ oneof dirty_swap {
+ // The dirty the pages that have been swapped out.
+ int32 dirty_swap_kb = 8;
+ // The dirty the pages that have been swapped out, proportional.
+ int32 dirty_swap_pss_kb = 9;
+ }
+ }
+ message HeapInfo {
+ optional MemoryInfo mem_info = 1;
+ optional int32 heap_size_kb = 2;
+ optional int32 heap_alloc_kb = 3;
+ optional int32 heap_free_kb = 4;
+ }
+ optional HeapInfo native_heap = 3;
+ optional HeapInfo dalvik_heap = 4;
+ repeated MemoryInfo other_heaps = 5;
+ optional HeapInfo unknown_heap = 6;
+ // Summation of native_heap, dalvik_heap, and other_heaps.
+ optional HeapInfo total_heap = 7;
+
+ repeated MemoryInfo dalvik_details = 8;
+
+ message AppSummary {
+ optional int32 java_heap_pss_kb = 1;
+ optional int32 native_heap_pss_kb = 2;
+ optional int32 code_pss_kb = 3;
+ optional int32 stack_pss_kb = 4;
+ optional int32 graphics_pss_kb = 5;
+ optional int32 private_other_pss_kb = 6;
+ optional int32 system_pss_kb = 7;
+
+ oneof total_swap {
+ int32 total_swap_pss = 8;
+ int32 total_swap_kb = 9;
+ }
+ }
+ optional AppSummary app_summary = 9;
+ }
+ repeated NativeProcess native_processes = 3;
+}
+
message StickyBroadcastProto {
optional int32 user = 1;
diff --git a/core/proto/android/server/alarmmanagerservice.proto b/core/proto/android/server/alarmmanagerservice.proto
index d2cd190..d724437 100644
--- a/core/proto/android/server/alarmmanagerservice.proto
+++ b/core/proto/android/server/alarmmanagerservice.proto
@@ -20,6 +20,7 @@
import "frameworks/base/core/proto/android/app/pendingintent.proto";
import "frameworks/base/core/proto/android/internal/locallog.proto";
import "frameworks/base/core/proto/android/os/worksource.proto";
+import "frameworks/base/core/proto/android/server/forceappstandbytracker.proto";
package com.android.server;
@@ -32,10 +33,9 @@
optional int64 last_time_change_realtime = 4;
// Current settings
optional ConstantsProto settings = 5;
- // UIDs currently in the foreground.
- repeated int32 foreground_uids = 6;
- // Packages forced into app standby.
- repeated string forced_app_standby_packages = 7;
+
+ // Dump from ForceAppStandbyTracker.
+ optional ForceAppStandbyTrackerProto force_app_standby_tracker = 6;
optional bool is_interactive = 8;
// Only valid if is_interactive is false.
diff --git a/core/proto/android/server/forceappstandbytracker.proto b/core/proto/android/server/forceappstandbytracker.proto
new file mode 100644
index 0000000..8753bf7
--- /dev/null
+++ b/core/proto/android/server/forceappstandbytracker.proto
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package com.android.server;
+
+option java_multiple_files = true;
+
+// Dump from ForceAppStandbyTracker.
+message ForceAppStandbyTrackerProto {
+ // Whether all apps are forced standby or not.
+ optional bool force_all_apps_standby = 1;
+
+ // UIDs currently in the foreground.
+ repeated int32 foreground_uids = 2;
+
+ // App ids that are in power-save whitelist.
+ repeated int32 power_save_whitelist_app_ids = 3;
+
+ // App ids that are in temporary power-save whitelist.
+ repeated int32 temp_power_save_whitelist_app_ids = 4;
+
+ message RunAnyInBackgroundRestrictedPackages {
+ optional int32 uid = 1;
+ optional string package_name = 2;
+ }
+
+ // Packages that are disallowed OP_RUN_ANY_IN_BACKGROUND.
+ repeated RunAnyInBackgroundRestrictedPackages run_any_in_background_restricted_packages = 5;
+}
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 0228edb..915fe9d 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -200,6 +200,7 @@
message WindowContainerProto {
optional ConfigurationContainerProto configuration_container = 1;
optional int32 orientation = 2;
+ optional bool visible = 3;
}
/* represents ConfigurationContainer */
diff --git a/core/proto/android/service/battery.proto b/core/proto/android/service/battery.proto
index 8382b82..4cb7fd3 100644
--- a/core/proto/android/service/battery.proto
+++ b/core/proto/android/service/battery.proto
@@ -46,9 +46,11 @@
optional bool are_updates_stopped = 1;
// Plugged status of power sources
optional android.os.BatteryManagerProto.PlugType plugged = 2;
- // Max current in microamperes
+ // Max current in microamperes. This may be 0 if the device's kernel drivers
+ // don't support it.
optional int32 max_charging_current = 3;
- // Max voltage
+ // Max voltage. This may be 0 if the device's kernel drivers don't support
+ // it.
optional int32 max_charging_voltage = 4;
// Battery capacity in microampere-hours
optional int32 charge_counter = 5;
diff --git a/core/res/Android.bp b/core/res/Android.bp
new file mode 100644
index 0000000..e66f1a2
--- /dev/null
+++ b/core/res/Android.bp
@@ -0,0 +1,41 @@
+//
+// Copyright (C) 2008 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+android_app {
+ name: "framework-res",
+ no_framework_libs: true,
+ certificate: "platform",
+
+ // Soong special-cases framework-res to install this alongside
+ // the libraries at /system/framework/framework-res.apk.
+
+ // Generate private symbols into the com.android.internal.R class
+ // so they are not accessible to 3rd party apps.
+ aaptflags: [
+ "--private-symbols",
+ "com.android.internal",
+
+ // Framework doesn't need versioning since it IS the platform.
+ "--no-auto-version",
+
+ // Allow overlay to add resource
+ "--auto-add-overlay",
+ ],
+
+ // Create package-export.apk, which other packages can use to get
+ // PRODUCT-agnostic resource data like IDs and type definitions.
+ export_package_resources: true,
+}
diff --git a/core/res/Android.mk b/core/res/Android.mk
deleted file mode 100644
index 370a01f..0000000
--- a/core/res/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# Copyright (C) 2008 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.
-#
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_PACKAGE_NAME := framework-res
-LOCAL_CERTIFICATE := platform
-LOCAL_MODULE_TAGS := optional
-
-# Generate private symbols into the com.android.internal.R class
-# so they are not accessible to 3rd party apps.
-LOCAL_AAPT_FLAGS += --private-symbols com.android.internal
-
-# Framework doesn't need versioning since it IS the platform.
-LOCAL_AAPT_FLAGS += --no-auto-version
-
-# Allow overlay to add resource
-LOCAL_AAPT_FLAGS += --auto-add-overlay
-
-# Install this alongside the libraries.
-LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)
-
-# Create package-export.apk, which other packages can use to get
-# PRODUCT-agnostic resource data like IDs and type definitions.
-LOCAL_EXPORT_PACKAGE_RESOURCES := true
-
-include $(BUILD_PACKAGE)
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d15c075..0920426 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1036,7 +1036,7 @@
<eat-comment />
<!-- Used for permissions that are associated with accessing
- camera or capturing images/video from the device. -->
+ body or environmental sensors. -->
<permission-group android:name="android.permission-group.SENSORS"
android:icon="@drawable/perm_group_sensors"
android:label="@string/permgrouplab_sensors"
@@ -1740,7 +1740,7 @@
@hide
-->
<permission android:name="android.permission.BIND_IMS_SERVICE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged|vendorPrivileged" />
<!-- Allows an application to manage embedded subscriptions (those on a eUICC) through
EuiccManager APIs.
@@ -2058,6 +2058,11 @@
<eat-comment />
<!-- Allows an application to install a shortcut in Launcher.
+ <p>In Android O (API level 26) and higher, the <code>INSTALL_SHORTCUT</code> broadcast no
+ longer has any effect on your app because it's a private, implicit
+ broadcast. Instead, you should create an app shortcut by using the
+ {@link android.content.pm.ShortcutManager#requestPinShortcut requestPinShortcut()}
+ method from the {@link android.content.pm.ShortcutManager} class.
<p>Protection level: normal
-->
<permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"
@@ -3611,6 +3616,11 @@
<permission android:name="android.permission.ACCESS_SHORTCUTS"
android:protectionLevel="signature" />
+ <!-- @SystemApi Allows an application to read the runtime profiles of other apps.
+ @hide <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.READ_RUNTIME_PROFILES"
+ android:protectionLevel="signature|privileged" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
diff --git a/core/res/res/drawable/btn_colored_material.xml b/core/res/res/drawable/btn_colored_material.xml
index c3c5760..7ba21e8 100644
--- a/core/res/res/drawable/btn_colored_material.xml
+++ b/core/res/res/drawable/btn_colored_material.xml
@@ -23,7 +23,7 @@
<item>
<shape android:shape="rectangle"
android:tint="@color/btn_colored_background_material">
- <corners android:radius="@dimen/control_corner_material" />
+ <corners android:radius="?attr/buttonCornerRadius" />
<solid android:color="@color/white" />
<padding android:left="@dimen/button_padding_horizontal_material"
android:top="@dimen/button_padding_vertical_material"
diff --git a/core/res/res/drawable/btn_default_mtrl_shape.xml b/core/res/res/drawable/btn_default_mtrl_shape.xml
index 8a31d5e..9d9cd06 100644
--- a/core/res/res/drawable/btn_default_mtrl_shape.xml
+++ b/core/res/res/drawable/btn_default_mtrl_shape.xml
@@ -23,7 +23,7 @@
android:insetBottom="@dimen/button_inset_vertical_material">
<shape android:shape="rectangle"
android:tint="?attr/colorButtonNormal">
- <corners android:radius="@dimen/control_corner_material" />
+ <corners android:radius="?attr/buttonCornerRadius" />
<solid android:color="@color/white" />
<padding android:left="@dimen/button_padding_horizontal_material"
android:top="@dimen/button_padding_vertical_material"
diff --git a/core/res/res/drawable/ic_logout.xml b/core/res/res/drawable/ic_logout.xml
new file mode 100644
index 0000000..c016ec8
--- /dev/null
+++ b/core/res/res/drawable/ic_logout.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <group>
+ <clip-path android:pathData="M0,0h24v24H0V0z M 0,0" />
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M17.0,7.0l-1.4099998,1.4099998l2.58,2.5900002l-10.17,0.0l0.0,2.0l10.17,0.0l-2.58,2.58l1.4099998,1.4200001l5.0,-5.0z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M4,5h8V3H4C2.9,3,2,3.9,2,5v14c0,1.1,0.9,2,2,2h8v-2H4V5z"/>
+ </group>
+</vector>
diff --git a/core/res/res/layout/notification_material_action_list.xml b/core/res/res/layout/notification_material_action_list.xml
index caeb43a..49b0ee7 100644
--- a/core/res/res/layout/notification_material_action_list.xml
+++ b/core/res/res/layout/notification_material_action_list.xml
@@ -23,7 +23,8 @@
android:id="@+id/actions"
android:layout_width="match_parent"
android:layout_height="@dimen/notification_action_list_height"
- android:paddingEnd="4dp"
+ android:paddingEnd="12dp"
+ android:paddingStart="8dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:visibility="gone"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 5f65553..66e4c09 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Geen stem- of nooddiens nie"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Word tydelik nie deur die selnetwerk by jou ligging aangebied nie"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Kan netwerk nie bereik nie"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Om opvangs te verbeter, probeer die soort verander wat by Instellings > Netwerk en internet > Mobiele netwerke > Voorkeurnetwerksoort gekies is."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Om opvangs te verbeter, probeer die tipe verander wat by Instellings > Netwerk en internet > Mobiele netwerke > Voorkeurnetwerktipe gekies is."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi-oproepe is aktief"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Noodoproepe vereis \'n mobiele netwerk."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Opletberigte"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Heraktiveer hierdie in Stelselinstellings > Programme > Afgelaai."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> steun nie die huidige skermgrootte-instelling nie en sal dalk onverwags reageer."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Wys altyd"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> is gebou vir \'n onversoenbare weergawe van die Android-bedryfstelsel en kan dalk op \'n onverwagte manier reageer. \'n Opgedateerde weergawe van die program is dalk beskikbaar."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Wys altyd"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Kyk vir opdatering"</string>
<string name="smv_application" msgid="3307209192155442829">"Die program <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) het sy selfopgelegde StrictMode-beleid oortree."</string>
<string name="smv_process" msgid="5120397012047462446">"Die proses <xliff:g id="PROCESS">%1$s</xliff:g> het die selfopgelegde StrictMode-beleid geskend."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android gradeer tans op..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Meld by netwerk aan"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi het geen internettoegang nie"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi‑Fi het geen internettoegang nie"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tik vir opsies"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Het oorgeskakel na <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Toestel gebruik <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internetverbinding het nie. Heffings kan geld."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Toestel gebruik <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internettoegang het nie. Heffings kan geld."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Het oorgeskakel van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobiele data"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"\'n onbekende netwerktipe"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kon nie aan Wi-Fikoppel nie"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" het \'n swak internetverbinding."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" het \'n swak internetverbinding."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Laat verbinding toe?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Program %1$s wil aan Wi-Fi-netwerk %2$s koppel"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"\'n Program"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2e werk-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3e werk-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Raak en hou die Terug- en Oorsig-knoppie om hierdie skerm te ontspeld"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Hierdie program kan nie ontspeld word nie"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Skerm vasgespeld"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Skerm ontspeld"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vra PIN voordat jy ontspeld"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Geïnstalleer deur jou administrateur"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Opgedateer deur jou administrateur"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Uitgevee deur jou administrateur"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Om batterylewe te help verbeter, verminder batterybespaarder jou toestel se werkverrigting en beperk vibrasie, liggingdienste en die meeste agtergronddata. E-pos, boodskappe en ander programme wat op sinkronisering staatmaak, sal dalk nie opdateer tensy jy hulle oopmaak nie.\n\nBatterybespaarder skakel outomaties af wanneer jou toestel besig is om te laai."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Om batterylewe te help verbeter, verminder Batterybespaarder jou toestel se werkverrigting en beperk vibrasie, liggingdienste en die meeste agtergronddata. E-pos, boodskappe en ander programme wat op sinkronisering staatmaak, sal dalk nie opdateer tensy jy hulle oopmaak nie.\n\nBatterybespaarder skakel outomaties af wanneer jou toestel besig is om te laai."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Databespaarder verhoed sommige programme om data in die agtergrond te stuur of te aanvaar om datagebruik te help verminder. \'n Program wat jy tans gebruik kan by data ingaan, maar sal dit dalk minder gereeld doen. Dit kan byvoorbeeld beteken dat prente nie wys totdat jy op hulle tik nie."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Skakel Databespaarder aan?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Skakel aan"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Noodboodskappetoets"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Antwoord"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM nie toegelaat vir stem nie"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM nie opgestel vir stem nie"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM nie toegelaat vir stem nie"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Foon nie toegelaat vir stem nie"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Opspringvenster"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Hierdie kortpad vereis die jongste program"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index c4be6f4..318fe81 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"ምንም የድምፅ እና የድንገተኛ አደጋ ጥሪ አገልግሎት የለም"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"ለጊዜው በአካባቢዎ ባለው የተንቀሳቃሽ ስልክ አውታረ መረብ አይቀርብም"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"አውታረ መረብ ላይ መድረስ አይቻልም"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"ቅበላን ለማሻሻል የተመረጠውን ዓይነት በቅንብሮች > አውታረ መረብ እና በይነመረብ > የተንቀሳቃሽ ስልክ አውታረ መረቦች > ተመራጭ የአውታረ መረብ ዓይነት ላይ ለመለወጥ ይሞክሩ።"</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"ቅበላን ለማሻሻል የተመረጠውን ዓይነት በቅንብሮች > አውታረ መረብ እና በይነመረብ > የተንቀሳቃሽ ስልክ አውታረ መረቦች > ተመራጭ የአውታረ መረብ ዓይነት ላይ ለመለወጥ ይሞክሩ።"</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"የWi‑Fi ጥሪ ገቢር ነው"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"የአደጋ ጥሪዎች የተንቀሳቃሽ ስልክ አውታረ መረብ ያስፈልጋቸዋል።"</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"ማንቂያዎች"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"በስርዓት ቅንብሮች ውስጥ ይሄንን ዳግም አንቃ> Apps &gt፤ወርዷል፡፡"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> አሁን ያለውን የማሳያ መጠን ቅንብር አይደግፍም እና ያልተጠብቀ ባሕሪ ሊያሳይ ይችላል።"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ሁልጊዜ አሳይ"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> ተኳሃኝ ላልሆነ የAndroid ስርዓተ ክወና ስሪት የተገነባ ሲሆን ያልተጠበቀ ባህሪን ሊያሳይ ይችላል። የተዘመነ የመተግበሪያው ስሪት ሊገኝ ይችላል።"</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"ሁልጊዜ አሳይ"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"ዝማኔ ካለ አረጋግጥ"</string>
<string name="smv_application" msgid="3307209192155442829">"መተግበሪያው <xliff:g id="APPLICATION">%1$s</xliff:g>( ሂደት<xliff:g id="PROCESS">%2$s</xliff:g>) በራስ ተነሳሺ StrictMode ደንብን ይተላለፋል።"</string>
<string name="smv_process" msgid="5120397012047462446">"ሂደቱ <xliff:g id="PROCESS">%1$s</xliff:g> በራስ ተነሳሺ StrictMode ፖሊሲን ይተላለፋል።"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android እያሻሻለ ነው..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"ወደ አውታረ መረብ በመለያ ይግቡ"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi በይነመረብ መዳረሻ የለውም"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi በይነመረብ መዳረሻ የለውም"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ለአማራጮች መታ ያድርጉ"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"ወደ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ተቀይሯል"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ምንም ዓይነት የበይነመረብ ግንኙነት በማይኖረው ጊዜ መሣሪያዎች <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ን ይጠቀማሉ። ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ።"</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ምንም ዓይነት የበይነመረብ ግንኙነት በማይኖረው ጊዜ መሣሪያዎች <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ን ይጠቀማሉ። ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ።"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"ከ<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ወደ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ተቀይሯል"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"የተንቀሳቃሽ ስልክ ውሂብ"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"አንድ ያልታወቀ አውታረ መረብ ዓይነት"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ወደ Wi-Fi ለማያያዝ አልተቻለም"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ደካማ የበይነመረብ ግንኙነት ኣለው።"</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ደካማ የበይነመረብ ግንኙነት ኣለው፡፡"</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"ግንኙነት ይፈቀድ?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"መተግበሪያ %1$s ወደ Wifi Network %2$s መገናኘት ይፈልጋል"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"አንድ መተግበሪያ"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2ኛ ስራ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3ኛ ስራ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"ይህን ማያ ገጽ ለመንቀል ተመለስ እና አጠቃላይ ዕይታን ተጭነው ይያዙ"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"ይህ መተግበሪያ እንዲነቀል ማድረግ አይቻልም"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"ማያ ገጽ ተሰክቷል"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"ማያ ገጽ ተነቅሏል"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ከመንቀል በፊት ፒን ጠይቅ"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"በእርስዎ አስተዳዳሪ ተጭኗል"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"በእርስዎ አስተዳዳሪ ተዘምኗል"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"በእርስዎ አስተዳዳሪ ተሰርዟል"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"የባትሪ ዕድሜን ለማሻሻል ማገዝ እንዲቻል፣ ኢሜይል፣ መልዕክት አላላክ እና ሌሎች በማመሳሰል ላይ የሚመረኮዙ መተግበሪያዎች እርስዎ ካልከፈቱዋቸው በቀር አይዘምኑም።\n\nየባትሪ ኃይል ቆጣቢ የእርስዎ መሣሪያ ኃይል በሚሞላበት ጊዜ በራስ-ሰር ይጠፋል።"</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"የባትሪ ዕድሜን እንዲሻሻል ለማገዝ የመሣሪያዎን አፈጻጸም ይቀንሳል እና ንዝረትን፣ የአካባቢ አገልግሎቶችን እና አብዛኛው ውሂብ ይገድባል። ኢሜይል፣ መልዕክት መላላኪያ እና ሌሎች በስምረት ላይ የሚወሰኑ መተግበሪያዎች እርስዎ ካልከፈቷቸው በስተቀር ላይዘመኑ ይችላሉ።\n\nየእርስዎ መሣሪያ ኃይል በሚሞላበት ጊዜ ባትሪ ቆጣቢ በራስ-ሰር ይጠፋል።"</string>
<string name="data_saver_description" msgid="6015391409098303235">"የውሂብ አጠቃቀም እንዲቀንስ ለማገዝ ውሂብ ቆጣቢ አንዳንድ መተግበሪያዎች ከበስተጀርባ ሆነው ውሂብ እንዳይልኩ ወይም እንዳይቀበሉ ይከለክላቸዋል። በአሁኑ ጊዜ እየተጠቀሙበት ያለ መተግበሪያ ውሂብ ሊደርስ ይችላል፣ ነገር ግን ባነሰ ተደጋጋሚነት ሊሆን ይችላል። ይሄ ማለት ለምሳሌ ምስሎችን መታ እስኪያደርጓቸው ድረስ ላይታዩ ይችላሉ ማለት ነው።"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ውሂብ ቆጣቢ ይጥፋ?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"አብራ"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"የአስቸኳይ አደጋ መልእክቶች ሙከራ"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"ምላሽ ስጥ"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"ሲም ለድምጽ አይፈቀድም"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"ሲም ለድምጽ አልቀረበም"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"ሲም ለድምጽ አይፈቀድም"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"ስልክ ለድምጽ አይፈቀድም"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"ብቅ-ባይ መስኮት"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"ይህ አቋራጭ በጣም የቅርብ ጊዜውን መተግበሪያ ይፈልጋል"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index cea9cd7..02345e2 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -83,7 +83,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"لا تتوفر خدمة الصوت/الطوارئ"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"مؤقتا لا تقدمها شبكة الجوال في موقعك"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"يتعذر الوصول إلى الشبكة"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"لتحسين الاستقبال، يمكنك محاولة تغيير النوع المحدّد من خلال الإعدادات > الشبكة والإنترنت > شبكات الجوّال > نوع الشبكة المفضّل."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"لتحسين الاستقبال، يمكنك محاولة تغيير النوع المحدّد من خلال الإعدادات > الشبكة والإنترنت > شبكات الجوّال > نوع الشبكة المفضّل."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"الاتصال عبر Wi-Fi نشط"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"تتطلب مكالمات الطوارئ شبكة جوّال."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"التنبيهات"</string>
@@ -1131,6 +1131,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"يمكنك إعادة تمكين هذا في إعدادات النظام > التطبيقات > ما تم تنزيله."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> غير متوافق مع الإعداد الحالي لحجم شاشة العرض وربما يعمل بطريقة غير متوقعة."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"العرض دائمًا"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"تم تصميم <xliff:g id="APP_NAME">%1$s</xliff:g> لإصدار غير متوافق من نظام تشغيل Android وقد يحدث خلل في أدائه. قد يتوفّر إصدار محدّث من التطبيق."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"الإظهار دائمًا"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"البحث عن تحديث"</string>
<string name="smv_application" msgid="3307209192155442829">"انتهك التطبيق <xliff:g id="APPLICATION">%1$s</xliff:g> (العملية <xliff:g id="PROCESS">%2$s</xliff:g>) سياسة StrictMode المفروضة ذاتيًا."</string>
<string name="smv_process" msgid="5120397012047462446">"انتهكت العملية <xliff:g id="PROCESS">%1$s</xliff:g> سياسة StrictMode المفروضة ذاتيًا."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"جارٍ ترقية Android..."</string>
@@ -1204,10 +1207,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"تسجيل الدخول إلى الشبكة"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"شبكة Wi-Fi غير متصلة بالإنترنت"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"شبكة Wi-Fi غير متصلة بالإنترنت"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"انقر للحصول على الخيارات."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"تم التبديل إلى <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"يستخدم الجهاز <xliff:g id="NEW_NETWORK">%1$s</xliff:g> عندما لا يتوفر اتصال بالإنترنت في شبكة <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>، ويمكن أن يتم فرض رسوم مقابل ذلك."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"يستخدم الجهاز <xliff:g id="NEW_NETWORK">%1$s</xliff:g> عندما لا يتوفر اتصال بالإنترنت في شبكة <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>، ويمكن أن يتم فرض رسوم مقابل ذلك."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"تم التبديل من <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> إلى <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"بيانات الجوّال"</item>
@@ -1218,7 +1221,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"نوع شبكة غير معروف"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"تعذر الاتصال بـ Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" لديها اتصال إنترنت رديء."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" تحتوي على اتصال إنترنت ضعيف."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"هل تريد السماح بالاتصال؟"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"يريد تطبيق %1$s الاتصال بشبكة Wifi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"تطبيق"</string>
@@ -1734,7 +1737,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"تم التثبيت بواسطة المشرف"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"تم التحديث بواسطة المشرف"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"تم الحذف بواسطة المشرف"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"للمساعدة في تحسين عمر البطارية، يساعد موفّر البطارية في تقليل أداء الجهاز والحد من الاهتزاز وخدمات الموقع ومعظم بيانات الخلفية، بالإضافة إلى عدم تحديث البريد الإلكتروني والمراسلة والتطبيقات الأخرى التي تعتمد على المزامنة ما لم يتم فتحها.\n\nيتم إيقاف موفّر البطارية تلقائيًا أثناء شحن الجهاز."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"للمساعدة في تحسين عمر البطارية، تساعد ميزة توفير شحن البطارية في تقليل أداء الجهاز والحد من الاهتزاز وخدمات المواقع الجغرافي ومعظم بيانات الخلفية. وقد لا يتم تحديث البريد الإلكتروني والمراسلة والتطبيقات الأخرى التي تعتمد على المزامنة ما لم يتم فتحها.\n\nيتم إيقاف ميزة توفير شحن البطارية تلقائيًا عند شحن الجهاز."</string>
<string name="data_saver_description" msgid="6015391409098303235">"للمساعدة في خفض استخدام البيانات، يمنع توفير البيانات بعض التطبيقات من إرسال البيانات وتلقيها في الخلفية. يمكن للتطبيق الذي تستخدمه الآن الوصول إلى البيانات، ولكن لا يمكنه تنفيذ ذلك كثيرًا. وهذا يعني أن الصور على سبيل المثال لا تظهر حتى تنقر عليها."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"هل تريد تشغيل توفير البيانات؟"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"تشغيل"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 40b5473..6041eeb 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Səsli/təcili xidmət yoxdur"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Müvəqqəti olaraq məkanda mobil şəbəkə tərəfindən təklif edilmir"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Şəbəkəyə daxil olmaq mümkün deyil"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Qəbulu inkişaf etdirmək üçün seçilmiş növü Ayarlar > Şəbəkə və İnternet > Mobil şəbəkə > Tərcih edilən şəbəkə növü bölməsində dəyişə bilərsiniz."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Qəbulu inkişaf etdirmək üçün seçilmiş növü Ayarlar > Şəbəkə və internet > Mobil şəbəkə > Tərcih edilən şəbəkə növü bölməsində dəyişə bilərsiniz."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi zəngi aktivdir"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Təcili zənglər üçün mobil şəbəkə tələb olunur."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Siqnallar"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Bunları Sistem ayarlarında yenidən aktivləşdir Yüklənmiş > Tətbiqlər >."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> cari Ekran ölçüsü ayarını dəstəkləmir və gözlənilməz şəkildə davrana bilər."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Həmişə göstərin"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> Android OS sisteminin uyğunsuz versiyası üçün hazırlandı və gözlənilməz şəkildə davrana bilər. Tətbiqin güncəllənmiş versiyası əlçatan ola bilər."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Həmişə göstərin"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Güncəlləməni yoxlayın"</string>
<string name="smv_application" msgid="3307209192155442829">"Tətbiq <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) StrictMode siyasətini pozdu."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> prosesi StrictMode siyasətini pozdu."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android təkmilləşdirilir..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Şəbəkəyə daxil olun"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-ın İnternetə girişi yoxdur"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi şəbəkəsinin internetə girişi yoxdur"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Seçimlər üçün tıklayın"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> şəbəkə növünə keçirildi"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> şəbəkəsinin İnternetə çıxışı olmadıqda, cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> şəbəkəsini istifadə edir. Ödəniş tətbiq oluna bilər."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> şəbəkəsinin internetə girişi olmadıqda, cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> şəbəkəsini istifadə edir. Xidmət haqqı tutula bilər."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> şəbəkəsindən <xliff:g id="NEW_NETWORK">%2$s</xliff:g> şəbəkəsinə keçirildi"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobil data"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"naməlum şəbəkə növü"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi\'a qoşulmaq alınmadı"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" internet bağlantısı keyfiyyətsizdir."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" zəif internet əlaqəsi var"</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Bağlantıya icazə verilsin?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Proqram %1$s Wifi Şəbəkəsinə qoşulmaq istəyir %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Tətbiq"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2-ci İş <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3-cü İş <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Bu ekrandan sancağı götürmək üçün Geri və İcmal düymələrinə basıb saxlayın"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Bu tətbiqdən sancağı götürmək alınmadı"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Screen pinned"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Screen unpinned"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ayırmadan öncə PIN istənilsin"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Admin tərəfindən quraşdırıldı"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Admin tərəfindən yeniləndi"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Admin tərəfindən silindi"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Batareyanın istismar müddətini təkmilləşdirmək üçün batareya qənaəti cihazınızın məhsuldarlığını azaldır və titrətmə, məkan xidmətləri və ən son fon məlumatlarını məhdudlaşdırır. Sinxronlaşmaya arxayın olan e-poçt, mesajlaşma və digər proqramlar siz onları açmayana kimi yenilənməyə bilər.\n\nCihazınız doldurulan zaman batareya qənaəti avtomatik olaraq sönür."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Batareyanın istifadə müddətini təkmilləşdirmək üçün Batareya Qənaəti cihazın performansını azaldıraq titrətmə, məkan xidmətləri və arxa fon məlumatlarını məhdudlaşdırır. Sinxronizasiyaya etibar edən e-poçt, mesajlaşma və digər tətbiqlər Siz onları açmayana kimi güncəllənməyə bilər.\n\nCihaz doldurulan zaman Batareya Qənaəti avtomatik olaraq sönür."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Data istifadəsini azalatmaq üçün, Data Qanaəti bəzi tətbiqlərin arxafonda data göndərməsini və qəbulunun qarşısını alır. Hazırda istifadə etdiyiniz tətbiq dataya daxil ola bilər, lakin çox az hissəsini tez-tez edə bilər. Bu o deməkdir ki, məsələn, üzərinə tıklamadıqca o şəkillər göstərilməyəcək."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Data Qənaəti aktiv edilsin?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Aktivləşdirin"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Təcili mesaj testi"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Cavablayın"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"Səs üçün SIM-ə icazə verilmir"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM səs üçün konfiqurasiya edilməyib"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"Səs üçün SIM-ə icazə verilmir"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Səs üçün telefona icazə verilmir"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Popap Pəncərəsi"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Bu qısayol ən son tətbiqi tələb edir"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 7a90719..055bccb 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -80,7 +80,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Nema glasovne usluge/usluge za hitne pozive"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Privremeno je onemogućeno na mobilnoj mreži na vašoj lokaciji"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Povezivanje sa mrežom nije uspelo"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Da biste poboljšali prijem, probajte da promenite izabrani tip u odeljku Podešavanja > Mreža i internet > Mobilne mreže > Željeni tip mreže."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Da biste poboljšali prijem, probajte da promenite izabrani tip u odeljku Podešavanja > Mreža i internet > Mobilne mreže > Željeni tip mreže."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi pozivanje je aktivno"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Hitni pozivi zahtevaju mobilnu mrežu."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Obaveštenja"</string>
@@ -1071,6 +1071,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ponovo omogućite u meniju Sistemska podešavanja > Aplikacije > Preuzeto."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava trenutno podešavanje veličine prikaza i može da se ponaša neočekivano."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Uvek prikazuj"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je napravljena za nekompatibilnu verziju Android OS-a i može da se ponaša na neočekivan način. Možda je dostupna ažurirana verzija aplikacije."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Uvek prikaži"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Potraži ažuriranje"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) je prekršila samonametnute StrictMode smernice."</string>
<string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> je prekršio samonametnute StrictMode smernice."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android se nadograđuje…"</string>
@@ -1138,10 +1141,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Prijavite se na mrežu"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nema pristup internetu"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi nema pristup internetu"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Prešli ste na tip mreže <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Uređaj koristi tip mreže <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kada tip mreže <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu. Možda će se naplaćivati troškovi."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Uređaj koristi tip mreže <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kada tip mreže <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu. Možda će se naplaćivati troškovi."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Prešli ste sa tipa mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na tip mreže <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobilni podaci"</item>
@@ -1152,7 +1155,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nepoznat tip mreže"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nije moguće povezati sa Wi-Fi mrežom"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internet vezu."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ima lošu internet vezu."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Želite li da dozvolite povezivanje?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacija %1$s želi da se poveže na Wi-Fi mrežu %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikacija"</string>
@@ -1659,7 +1662,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Instalirao je administrator"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Ažurirao je administrator"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Izbrisao je administrator"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Da bi produžila vreme trajanja baterije, ušteda baterije smanjuje performanse uređaja i ograničava vibraciju, usluge lokacije i većinu pozadinskih podataka. Imejl, razmena poruka i druge aplikacije koje se oslanjaju na sinhronizaciju neće se ažurirati dok ih ne otvorite.\n\nUšteda baterije se automatski isključuje kada se uređaj puni."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Da bi produžila trajanje baterije, Ušteda baterije smanjuje performanse uređaja i ograničava vibraciju, usluge lokacije i većinu pozadinskih podataka. Imejl, razmena poruka i druge aplikacije koje se oslanjaju na sinhronizaciju se neće ažurirati ako ih ne otvorite.\n\nUšteda baterije se automatski isključuje kada se uređaj puni."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjila potrošnja podataka, Ušteda podataka sprečava neke aplikacije da šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može da pristupa podacima, ali će to činiti ređe. Na primer, slike se neće prikazivati dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Uključiti Uštedu podataka?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Uključi"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 10ead45..9f07c7e 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -81,7 +81,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Няма сэрвісу галасавых / экстранных выклікаў"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Часова не прапаноўваецца сеткай мабільнай сувязі ў вашым месцазанходжанні"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Немагчыма падключыцца да сеткі"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Каб палепшыць якасць прыёму, паспрабуйце змяніць тып, выбраны ў меню \"Налады > Сетка і інтэрнэт > Мабільныя сеткі > Прыярытэтны тып сеткі\"."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Каб палепшыць якасць прыёму, паспрабуйце змяніць тып, выбраны ў меню \"Налады > Сетка і інтэрнэт > Мабільныя сеткі > Прыярытэтны тып сеткі\"."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi-Fi-тэлефанія актыўная"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Для экстранных выклікаў патрабуецца мабільная сетка."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Абвесткі"</string>
@@ -1091,6 +1091,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Зноў уключыце гэта ў раздзеле \"Сістэмныя налады > Прыкладанні > Спампаваныя\"."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не падтрымлівае бягучую наладу Памеру дысплэя і можа паводзіць сябе непрадказальным чынам."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Заўсёды паказваць"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Праграма <xliff:g id="APP_NAME">%1$s</xliff:g> была створана для несумяшчальнай версии АС Android і можа паводзіць сябе неспадзявана. Можа быць даступна абноўленая версія праграмы."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Заўсёды паказваць"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Праверыць на наяўнасць абнаўленняў"</string>
<string name="smv_application" msgid="3307209192155442829">"Прыкладанне <xliff:g id="APPLICATION">%1$s</xliff:g> (працэс <xliff:g id="PROCESS">%2$s</xliff:g>) парушыла ўласную палітыку StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Працэс <xliff:g id="PROCESS">%1$s</xliff:g> парушыў уласную палітыку StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Абнаўленне Android..."</string>
@@ -1160,10 +1163,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Увайдзіце ў сетку"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"У Wi-Fi няма доступу да Інтэрнэту"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"У Wi-Fi няма доступу да інтэрнэту"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Дакраніцеся, каб убачыць параметры"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Выкананы пераход да <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Прылада выкарыстоўвае <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, калі ў <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма доступу да інтэрнэту. Можа спаганяцца дадатковая плата."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Прылада выкарыстоўвае сетку <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, калі ў сетцы <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма доступу да інтэрнэту. Можа спаганяцца плата."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Выкананы пераход з <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> да <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"мабільная перадача даных"</item>
@@ -1174,7 +1177,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"невядомы тып сеткі"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Немагчыма падключыцца да Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" дрэннае падключэнне да Інтэрнэту."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" дрэннае падключэнне да Інтэрнэту."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дазволіць падключэнне?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Праграма %1$s хоча падлучыцца да сеткі Wi-Fi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Праграма"</string>
@@ -1684,7 +1687,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Усталяваны вашым адміністратарам"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Абноўлены вашым адміністратарам"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Выдалены вашым адміністратарам"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Каб падоўжыць час працы акумулятара, у рэжыме эканоміі зараду памяншаецца прадукцыйнасць вашай прылады, абмяжоўваецца выкарыстанне вібрацыі, службаў вызначэння месцазнаходжання і большасці задач фонавай перадачы даных. Электронная пошта, абмен паведамленнямі і іншыя праграмы, якія выкарыстоўваюць сінхранізацыю, могуць не абнаўляцца, пакуль вы іх не адкрыеце.\n\nРэжым эканоміі зараду адключаецца аўтаматычна, калі прылада зараджаецца."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Каб падоўжыць час працы акумулятара, у рэжыме эканоміі зараду памяншаецца прадукцыйнасць вашай прылады, абмяжоўваецца выкарыстанне вібрацыі, службаў вызначэння месцазнаходжання і большасці задач фонавай перадачы даных. Электронная пошта, абмен паведамленнямі і іншыя праграмы, якія выкарыстоўваюць сінхранізацыю, могуць не абнаўляцца, пакуль вы іх не адкрыеце.\n\nРэжым эканоміі зараду адключаецца аўтаматычна, калі прылада зараджаецца."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Каб паменшыць выкарыстанне даных, Эканомія трафіку не дазваляе некаторым праграмам адпраўляць ці атрымліваць даныя ў фонавым рэжыме. Праграма, якую вы зараз выкарыстоўваеце, можа атрымліваць доступ да даных, але можа рабіць гэта радзей. Гэта можа азначаць, напрыклад, што відарысы не паказваюцца, пакуль вы не дакраняцеся да іх."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Уключыць Эканомію трафіка?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Уключыць"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index ccdeb24..ba6459b 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Няма услуга за гласови/спешни обаждания"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Временно не се предлага от мобилната мрежа в местоположението ви"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Не може да се установи връзка с мрежата"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"За да подобрите сигнала, променете избрания тип мрежа от „Настройки“ > „Мрежа и интернет“ > „Мобилни мрежи“ > „Предпочитан тип мрежа“."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"За да подобрите сигнала, променете избрания тип мрежа от „Настройки“ > „Мрежа и интернет“ > „Мобилни мрежи“ > „Предпочитан тип мрежа“."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Функцията за обаждания през Wi-Fi е активна"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"За спешните обаждания се изисква мобилна мрежа."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Сигнали"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Активирайте отново това в „Системни настройки“ > „Приложения“ > „Изтеглени“."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддържа текущата настройка за размер на дисплея и може да се държи по неочакван начин."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Винаги да се показва"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Приложението <xliff:g id="APP_NAME">%1$s</xliff:g> бе създадено за несъвместима версия на операционната система Android и може да се държи по неочакван начин. Възможно е да е налице актуализирана версия."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Винаги да се показва"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Проверка за актуализация"</string>
<string name="smv_application" msgid="3307209192155442829">"Приложението „<xliff:g id="APPLICATION">%1$s</xliff:g>“ (процес „<xliff:g id="PROCESS">%2$s</xliff:g>“) наруши правилото за стриктен режим, наложено от самото него."</string>
<string name="smv_process" msgid="5120397012047462446">"Процесът <xliff:g id="PROCESS">%1$s</xliff:g> наруши правилото за стриктен режим, наложено от самия него."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android се надстройва..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Вход в мрежата"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi мрежата няма достъп до интернет"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi мрежата няма достъп до интернет"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Докоснете за опции"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Превключи се към <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Устройството използва <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, когато <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма достъп до интернет. Възможно е да бъдете таксувани."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Устройството използва <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, когато <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма достъп до интернет. Възможно е да бъдете таксувани."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Превключи се от <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> към <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"мобилни данни"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"неизвестен тип мрежа"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не можа да се свърже с Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има лоша връзка с интернет."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" има лоша връзка с интернет."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Да се разреши ли връзката?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Приложението %1$s иска да се свърже с Wi-Fi мрежата „%2$s“"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Приложение"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Втори служебен профил (<xliff:g id="LABEL">%1$s</xliff:g>)"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Трети служебен профил (<xliff:g id="LABEL">%1$s</xliff:g>)"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"За да освободите този екран, докоснете и задръжте бутона за връщане назад и този за общ преглед"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Това приложение не може да бъде освободено"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Екранът е фиксиран"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Екранът е освободен"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Запитване за ПИН код преди освобождаване"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Инсталирано от администратора ви"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Актуализирано от администратора ви"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Изтрито от администратора ви"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"С цел удължаване на живота на батерията режимът за запазването й намалява ефективността на устройството ви и ограничава вибрирането, услугите за местоположение и повечето данни на заден план. Приложенията за електронна поща, съобщения и др., които разчитат на синхронизиране, може да не се актуализират, освен ако не ги отворите.\n\nРежимът за запазване на батерията се изключва автоматично, когато устройството ви се зарежда."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"С цел удължаване на живота на батерията режимът за запазването й намалява ефективността на устройството ви и ограничава вибрирането, услугите за местоположение и повечето данни на заден план. Приложенията за електронна поща, съобщения и др., които разчитат на синхронизиране, може да не се актуализират, освен ако не ги отворите.\n\nРежимът за запазване на батерията се изключва автоматично, когато устройството ви се зарежда."</string>
<string name="data_saver_description" msgid="6015391409098303235">"С цел намаляване на преноса на данни функцията за икономия на данни не позволява на някои приложения да изпращат или получават данни на заден план. Понастоящем използвано от вас приложение може да използва данни, но по-рядко. Това например може да означава, че изображенията не се показват, докато не ги докоснете."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Ще вкл. ли Икономия на данни?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Включване"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Тест за спешни съобщения"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Отговор"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"Гласовите услуги не са разрешени за SIM картата"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM картата не е обезпечена за гласови услуги"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"Гласовите услуги не са разрешени за SIM картата"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Гласовите услуги не са разрешени за телефона"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Изскачащ прозорец"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"За този пряк път се изисква най-новата версия на приложението"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index b4240cd..440b2690 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -79,8 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"কোনো ভয়েস/জরুরী পরিষেবা নেই"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"সাময়িকভাবে মোবাইল নেটওয়ার্ক আপনার অবস্থানে এই পরিষেবা দিচ্ছে না"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"নেটওয়ার্কের সিগন্যাল নেই"</string>
- <!-- no translation found for NetworkPreferenceSwitchSummary (7056776609127756440) -->
- <skip />
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"আরও ভাল সিগন্যাল পাওয়ার জন্য সেটিংস > নেটওয়ার্ক এবং ইন্টারনেট > মোবাইল নেটওয়ার্ক > পছন্দের নেটওয়ার্কের ধরন বিকল্পে গিয়ে অন্য ধরনের নেটওয়ার্ক বেছে নিয়ে দেখুন।"</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"ওয়াই-ফাই কলিং সক্রিয় আছে"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"জরুরি কলের জন্য মোবাইল নেটওয়ার্ক থাকতে হবে।"</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"সতর্কতা"</string>
@@ -213,6 +212,8 @@
<string name="global_action_power_off" msgid="4471879440839879722">"পাওয়ার বন্ধ করুন"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"জরুরী"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"ত্রুটির প্রতিবেদন"</string>
+ <!-- no translation found for global_action_logout (935179188218826050) -->
+ <skip />
<string name="bugreport_title" msgid="2667494803742548533">"ত্রুটির অভিযোগ করুন"</string>
<string name="bugreport_message" msgid="398447048750350456">"এটি একটি ই-মেল মেসেজ পাঠানোর জন্য আপনার ডিভাইসের বর্তমান অবস্থা সম্পর্কে তথ্য সংগ্রহ করবে৷ ত্রুটির প্রতিবেদন শুরুর সময় থেকে এটি পাঠানোর জন্য প্রস্তুত হতে কিছুটা সময় নেবে; অনুগ্রহ করে ধৈর্য রাখুন৷"</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"ইন্টারেক্টিভ প্রতিবেদন"</string>
@@ -1052,12 +1053,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"সিস্টেম সেটিংস> অ্যাপ্স> ডাউনলোড করাগুলি এ এটি পুনঃসক্ষম করুন৷"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g>, বর্তমান প্রদর্শনের আকারের সেটিংস সমর্থন করে না এবং অপ্রত্যাশিত আচরণ করতে পারে৷"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"সর্বদা দেখান"</string>
- <!-- no translation found for unsupported_compile_sdk_message (5030433583092006591) -->
- <skip />
- <!-- no translation found for unsupported_compile_sdk_show (2681877855260970231) -->
- <skip />
- <!-- no translation found for unsupported_compile_sdk_check_update (3312723623323216101) -->
- <skip />
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> Android OS এর একটি সামঞ্জস্যহীন ভার্সনের জন্য তৈরি করা হয়েছিল, তাই এখানে সেটি অস্বাভাবিক আচরণ করতে পারে। মনে হয় অ্যাপটির আপডেট করা ভার্সনও আছে।"</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"সবসময় দেখুন"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"আপডেট পাওয়া যাচ্ছে কিনা দেখুন"</string>
<string name="smv_application" msgid="3307209192155442829">"অ্যাপ্লিকেশানটি <xliff:g id="APPLICATION">%1$s</xliff:g> (প্রক্রিয়া <xliff:g id="PROCESS">%2$s</xliff:g>) তার স্ব-প্রয়োগ করা কঠোর মোড নীতি লঙ্ঘন করেছে৷"</string>
<string name="smv_process" msgid="5120397012047462446">"প্রক্রিয়াটি <xliff:g id="PROCESS">%1$s</xliff:g> তার স্ব-প্রয়োগ করা কঠোর মোড নীতি লঙ্ঘন করেছে৷"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android আপগ্রেড করা হচ্ছে..."</string>
@@ -1123,12 +1121,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"নেটওয়ার্কে সাইন-ইন করুন"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <!-- no translation found for wifi_no_internet (8938267198124654938) -->
- <skip />
+ <string name="wifi_no_internet" msgid="8938267198124654938">"ওয়াই-ফাই এ ইন্টারনেট অ্যাক্সেস নেই"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"বিকল্পগুলির জন্য আলতো চাপুন"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> এ পাল্টানো হয়েছে"</string>
- <!-- no translation found for network_switch_metered_detail (775163331794506615) -->
- <skip />
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> এ ইন্টারনেট অ্যাক্সেস না থাকলে <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ব্যবহার করা হয়৷ ডেটা চার্জ প্রযোজ্য৷"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> থেকে <xliff:g id="NEW_NETWORK">%2$s</xliff:g> এ পাল্টানো হয়েছে"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"মোবাইল ডেটা"</item>
@@ -1505,6 +1501,10 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"শর্টকাটটি চালু থাকলে দুটি ভলিউম বোতাম একসাথে ৩ সেকেন্ড টিপে ধরে রাখলে একটি অ্যাকসেসিবিলিটি বৈশিষ্ট্য চালু হবে।\n\n বর্তমান অ্যাকসেসিবিলিটি বৈশিষ্ট্য:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n আপনি এই বৈশিষ্ট্যটি সেটিংস > অ্যাকসেসিবিলিটিতে গিয়ে পরিবর্তন করতে পারবেন।"</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"শর্টকাট বন্ধ করুন"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"শর্টকাট ব্যবহার করুন"</string>
+ <!-- no translation found for color_inversion_feature_name (4231186527799958644) -->
+ <skip />
+ <!-- no translation found for color_correction_feature_name (6779391426096954933) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"অ্যাক্সেসযোগ্যতা শর্টকাট <xliff:g id="SERVICE_NAME">%1$s</xliff:g> কে চালু করেছে"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"অ্যাক্সেসযোগ্যতা শর্টকাট <xliff:g id="SERVICE_NAME">%1$s</xliff:g> কে বন্ধ করেছে"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"অ্যাক্সেসযোগ্যতা বোতামের সাহায্যে যে বৈশিষ্ট্যটি নিয়ন্ত্রণ করতে চান, সেটি বেছে নিন:"</string>
@@ -1644,7 +1644,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"আপনার প্রশাসক ইনস্টল করেছেন"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"আপনার প্রশাসক আপডেট করেছেন"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"আপনার প্রশাসক মুছে দিয়েছেন"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"ব্যাটরির লাইফ উন্নত করতে, ব্যাটারি সাশ্রয়কারী আপনার ডিভাইসের কার্যসম্পাদনা হ্রাস করে এবং কম্পন, লোকেশন পরিষেবাগুলি এবং অধিকাংশ ব্যাকগ্রাউন্ড ডেটা সীমিত করে৷ ইমেল, মেসেজিং এবং অন্যান্য অ্যাপ্লিকেশনগুলিকে যেগুলি সিঙ্কের উপর নির্ভর করে সেগুলিকে আপনি না খোলা পর্যন্ত নাও আপডেট হতে পারে৷\n\nআপনার ডিভাইসটিকে যখন চার্জ করা হয় তখন ব্যাটারি সাশ্রয়কারী নিজে থেকে বন্ধ হয়ে যায়৷"</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"ব্যাটরির লাইফ উন্নত করে সাহায্য করতে, ব্যাটারি সেভার আপনার ডিভাইসের পারফরম্যান্স কমিয়ে দেয় এবং কম্পন, লোকেশন পরিষেবা এবং অধিকাংশ ব্যাকগ্রাউন্ড ডেটা সীমিত করে। ইমেল, মেসেজিং এবং সিঙ্কের উপর নির্ভর করে এমন অন্যান্য অ্যাপগুলিকে আপনি না খোলা পর্যন্ত নাও আপডেট হতে পারে।\n\nআপনার ডিভাইসটিকে যখন চার্জ করা হয় তখন ব্যাটারি সেভার নিজে থেকে বন্ধ হয়ে যায়।"</string>
<string name="data_saver_description" msgid="6015391409098303235">"ডেটার ব্যবহার কমাতে সহায়তা করার জন্য, ডেটা সেভার পটভূমিতে কিছু অ্যাপ্লিকেশনকে ডেটা পাঠাতে বা গ্রহণ করতে বাধা দেয়৷ আপনি বর্তমানে এমন একটি অ্যাপ্লিকেশন ব্যবহার করছেন যেটি ডেটা অ্যাক্সেস করতে পারে, তবে সেটি কমই করে৷ এর ফলে যা হতে পারে, উদাহরণস্বরূপ, আপনি ছবিগুলিতে আলতো চাপ না দেওয়া পর্যন্ত সেগুলি প্রদর্শিত হবে না৷"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ডেটা সেভার চালু করবেন?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"চালু করুন"</string>
@@ -1691,6 +1691,8 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"সপ্তাহান্তের রাত্রি"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"সপ্তাহান্ত"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"ইভেন্ট"</string>
+ <!-- no translation found for zen_mode_default_every_night_name (3012363838882944175) -->
+ <skip />
<string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> দ্বারা নিঃশব্দ করা হয়েছে"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"আপনার ডিভাইসে একটি অভ্যন্তরীন সমস্যা হয়েছে, এবং আপনি যতক্ষণ না পর্যন্ত এটিকে ফ্যাক্টরি ডেটা রিসেট করছেন ততক্ষণ এটি ঠিকভাবে কাজ নাও করতে পারে৷"</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"আপনার ডিভাইসে একটি অভ্যন্তরীন সমস্যা হয়েছে৷ বিস্তারিত জানার জন্য প্রস্তুতকারকের সাথে যোগাযোগ করুন৷"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index aa83d1d..c9c98eb 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -80,7 +80,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Nema govornih/hitnih usluga"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Trenutno nije u ponudi mobilne mreže na vašoj lokaciji"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Nije moguće dosegnuti mrežu"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Da poboljšate prijem, pokušajte promijeniti odabranu vrstu u meniju Postavke < Mreža i internet < Mobilne mreže < Preferirana vrsta mreže."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Da poboljšate prijem, pokušajte promijeniti odabrani tip u meniju Postavke > Mreža i internet > Mobilne mreže > Preferirani tip mreže."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Aktivno je Wi‑Fi pozivanje"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Za hitne pozive potrebna je mreža"</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Upozorenja"</string>
@@ -214,6 +214,8 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Isključi telefon"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Hitno"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Izvještaj o greškama"</string>
+ <!-- no translation found for global_action_logout (935179188218826050) -->
+ <skip />
<string name="bugreport_title" msgid="2667494803742548533">"Kreirajte izvještaj o greškama"</string>
<string name="bugreport_message" msgid="398447048750350456">"Ovim će se prikupljati informacije o trenutnom stanju uređaja, koji će biti poslani kao e-poruka. Može malo potrajati dok se izvještaj o greškama ne kreira i bude spreman za slanje. Budite strpljivi."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktivni izvještaj"</string>
@@ -364,13 +366,13 @@
<string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Dozvoljava aplikaciji slanje ljepljivih informacija koje ostaju nakon prestanka emitiranja. Pretjeranom upotrebom može se usporiti ili destabilizirati rad TV-a zbog korištenja previše memorije."</string>
<string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Omogućava aplikaciji slanje ljepljivih informacija koje ostaju nakon prestanka emitiranja. Njihova pretjerana upotreba može usporiti ili destabilizirati rad telefona jer troši previše memorije."</string>
<string name="permlab_readContacts" msgid="8348481131899886131">"čitanje vaših kontakata"</string>
- <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Omogućava aplikaciji čitanje podataka o kontaktima koji su pohranjeni na vašem tabletu, uključujući učestalost vaših poziva, slanja e-pošte ili nekog drugog vida komunikacije sa određenim pojedincima. Ova dozvola omogućava aplikacijama da pohrane podatke o vašim kontaktima tako da ih zlonamjerne aplikacije mogu podijeliti bez vašeg znanja."</string>
- <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Dozvoljava aplikaciji da čita podatke o vašim kontaktima pohranjenim na TV-u, uključujući učestalost poziva, slanja e-pošte ili komuniciranja na bilo koji način s određenim osobama. Ovom dozvolom aplikacijama se omogućava da sačuvaju podatke o kontaktima, a zlonamjerne aplikacije mogu bez vašeg znanja podijeliti ove podatke."</string>
- <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Omogućava aplikaciji čitanje podataka o kontaktima koji su pohranjeni na vašem telefonu, uključujući učestalost vaših poziva, slanja e-pošte ili nekog drugog vida komunikacije sa određenim pojedincima. Ova dozvola omogućava aplikacijama da pohrane podatke o vašim kontaktima tako da ih zlonamjerne aplikacije mogu podijeliti bez vašeg znanja."</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Omogućava aplikaciji čitanje podataka o kontaktima koji su pohranjeni na vašem tabletu, uključujući učestalost vaših poziva, slanja e-pošte ili nekog drugog vida komunikacije sa određenim pojedincima. Ovo odobrenje omogućava aplikacijama da pohrane podatke o vašim kontaktima tako da ih zlonamjerne aplikacije mogu podijeliti bez vašeg znanja."</string>
+ <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Dozvoljava aplikaciji da čita podatke o vašim kontaktima pohranjenim na TV-u, uključujući učestalost poziva, slanja e-pošte ili komuniciranja na bilo koji način s određenim osobama. Ovim odobrenjem aplikacijama se omogućava da sačuvaju podatke o kontaktima, a zlonamjerne aplikacije mogu bez vašeg znanja podijeliti ove podatke."</string>
+ <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Omogućava aplikaciji čitanje podataka o kontaktima koji su pohranjeni na vašem telefonu, uključujući učestalost vaših poziva, slanja e-pošte ili nekog drugog vida komunikacije sa određenim pojedincima. Ovo odobrenje omogućava aplikacijama da pohrane podatke o vašim kontaktima tako da ih zlonamjerne aplikacije mogu podijeliti bez vašeg znanja."</string>
<string name="permlab_writeContacts" msgid="5107492086416793544">"izmjena podataka o kontaktima"</string>
- <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Omogućava aplikaciji da izmijeni podatke o kontaktima koji su pohranjeni na vašem tabletu, uključujući učestalost vaših poziva, slanje e-pošte, ili neki drugi vid komunikacije sa određenim kontaktima. Ova dozvola omogućava aplikaciji da obriše podatke o kontaktima."</string>
- <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Dozvoljava aplikaciji izmjenu podataka o vašim kontaktima pohranjenim na TV-u, uključujući učestalost poziva, slanja e-pošte ili komuniciranja na bilo koji način s određenim kontaktima. Ovom dozvolom aplikacijama se omogućava brisanje podataka o kontaktima."</string>
- <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Omogućava aplikaciji da izmijeni podatke o kontaktima koji su pohranjeni na vašem telefonu, uključujući učestalost vaših poziva, slanje e-pošte, ili neki drugi vid komunikacije sa određenim kontaktima. Ova dozvola omogućava aplikaciji da izbriše podatke o kontaktima."</string>
+ <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Omogućava aplikaciji da izmijeni podatke o kontaktima koji su pohranjeni na vašem tabletu, uključujući učestalost vaših poziva, slanje e-pošte, ili neki drugi vid komunikacije sa određenim kontaktima. Ovo odobrenje omogućava aplikaciji da obriše podatke o kontaktima."</string>
+ <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Dozvoljava aplikaciji izmjenu podataka o vašim kontaktima pohranjenim na TV-u, uključujući učestalost poziva, slanja e-pošte ili komuniciranja na bilo koji način s određenim kontaktima. Ovim odobrenjem aplikacijama se omogućava brisanje podataka o kontaktima."</string>
+ <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Omogućava aplikaciji da izmijeni podatke o kontaktima koji su pohranjeni na vašem telefonu, uključujući učestalost vaših poziva, slanje e-pošte, ili neki drugi vid komunikacije sa određenim kontaktima. Ovo odobrenje omogućava aplikaciji da izbriše podatke o kontaktima."</string>
<string name="permlab_readCallLog" msgid="3478133184624102739">"čitanje zapisnika poziva"</string>
<string name="permdesc_readCallLog" msgid="3204122446463552146">"Ova aplikacija može čitati historiju vaših poziva."</string>
<string name="permlab_writeCallLog" msgid="8552045664743499354">"pisanje zapisnika poziva"</string>
@@ -410,7 +412,7 @@
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"pristup usluzi IMS pozivanja"</string>
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Omogućava aplikaciji da koristi IMS uslugu za pozivanje bez vaše intervencije."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"čitanje statusa i identiteta telefona"</string>
- <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Omogućava aplikaciji pristup telefonskim funkcijama uređaja. Ova dozvola omogućava aplikaciji određivanje telefonskog i identifikacionog broja uređaja, bez obzira da li je poziv aktivan i da li je uspostavljena veza sa pozivanim brojem."</string>
+ <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Omogućava aplikaciji pristup telefonskim funkcijama uređaja. Ovo odobrenje omogućava aplikaciji određivanje telefonskog i identifikacionog broja uređaja, bez obzira da li je poziv aktivan i da li je uspostavljena veza sa pozivanim brojem."</string>
<string name="permlab_manageOwnCalls" msgid="1503034913274622244">"usmjeravanje poziva preko sistema"</string>
<string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Dopušta aplikaciji da pozive usmjeri preko sistema radi poboljšanja iskustva pozivanja."</string>
<string name="permlab_readPhoneNumbers" msgid="6108163940932852440">"čitanje telefonskih brojeva"</string>
@@ -832,11 +834,11 @@
<string name="autofill_area" msgid="3547409050889952423">"Oblast"</string>
<string name="autofill_emirate" msgid="2893880978835698818">"Emirat"</string>
<string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"čitanje internet oznaka i historije"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Omogućava aplikaciji čitanje historije URL-ova koje je preglednik posjetio, kao i svih oznaka preglednika. Napomena: ovu dozvolu ne mogu iskoristiti preglednici trećih strana ili druge aplikacije koje imaju mogućnost pregledanja interneta."</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Omogućava aplikaciji čitanje historije URL-ova koje je preglednik posjetio, kao i svih oznaka preglednika. Napomena: ovo odobrenje ne mogu iskoristiti preglednici trećih strana ili druge aplikacije koje imaju mogućnost pregledanja interneta."</string>
<string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"pisanje internet oznaka i historije"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Omogućava aplikaciji da izmijeni historiju ili oznake preglednika koji su pohranjeni na vašem tabletu. Ovim se aplikaciji može omogućiti da izbriše ili izmijeni podatke preglednika. Napomena: ovu dozvolu ne mogu koristiti preglednici trećih strana ili druge aplikacije koje imaju mogućnost pregledanja interneta."</string>
- <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"Dozvoljava aplikaciji izmjenu historije ili oznaka preglednika pohranjenih na TV-u. Ovim se aplikaciji može omogućiti brisanje ili izmjena podataka preglednika. Napomena: ovu dozvolu ne mogu iskoristiti preglednici trećih strana ili druge aplikacije koje imaju mogućnost pregleda interneta."</string>
- <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Omogućava aplikaciji da izmijeni historiju ili oznake preglednika koji su pohranjeni na vašem telefonu. Ovim se aplikaciji može omogućiti da izbriše ili izmijeni podatke preglednika. Napomena: ovu dozvolu ne mogu koristiti preglednika trećih strana ili druge aplikacije koje imaju mogućnost pregledanja interneta."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Omogućava aplikaciji da izmijeni historiju ili oznake preglednika koji su pohranjeni na vašem tabletu. Ovim se aplikaciji može omogućiti da izbriše ili izmijeni podatke preglednika. Napomena: ovo odobrenje ne mogu koristiti preglednici trećih strana ili druge aplikacije koje imaju mogućnost pregledanja interneta."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"Dozvoljava aplikaciji izmjenu historije ili oznaka preglednika pohranjenih na TV-u. Ovim se aplikaciji može omogućiti brisanje ili izmjena podataka preglednika. Napomena: ovo odobrenje ne mogu iskoristiti preglednici trećih strana ili druge aplikacije koje imaju mogućnost pregleda interneta."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Omogućava aplikaciji da izmijeni historiju ili oznake preglednika koji su pohranjeni na vašem telefonu. Ovim se aplikaciji može omogućiti da izbriše ili izmijeni podatke preglednika. Napomena: ovo odobrenje ne mogu koristiti preglednika trećih strana ili druge aplikacije koje imaju mogućnost pregledanja interneta."</string>
<string name="permlab_setAlarm" msgid="1379294556362091814">"postavljanje alarma"</string>
<string name="permdesc_setAlarm" msgid="316392039157473848">"Dozvoljava aplikaciji postavljanje alarma u instaliranom budilniku. Moguće je da neki budilnici neće primijeniti ovu funkciju."</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"dodavanje govorne pošte"</string>
@@ -847,7 +849,7 @@
<string name="save_password_notnow" msgid="6389675316706699758">"Ne sada"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Zapamti"</string>
<string name="save_password_never" msgid="8274330296785855105">"Nikad"</string>
- <string name="open_permission_deny" msgid="7374036708316629800">"Nemate dozvolu za otvaranje ove stranice."</string>
+ <string name="open_permission_deny" msgid="7374036708316629800">"Nemate odobrenje za otvaranje ove stranice."</string>
<string name="text_copied" msgid="4985729524670131385">"Tekst kopiran u međuspremnik."</string>
<string name="more_item_label" msgid="4650918923083320495">"Više"</string>
<string name="prepend_shortcut_label" msgid="2572214461676015642">"Meni+"</string>
@@ -1026,9 +1028,9 @@
<string name="whichEditApplication" msgid="144727838241402655">"Uredi koristeći"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Uredi koristeći %1$s"</string>
<string name="whichEditApplicationLabel" msgid="7183524181625290300">"Uredi"</string>
- <string name="whichSendApplication" msgid="6902512414057341668">"Podijeli koristeći"</string>
- <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Podijeli koristeći %1$s"</string>
- <string name="whichSendApplicationLabel" msgid="4579076294675975354">"Podijeli"</string>
+ <string name="whichSendApplication" msgid="6902512414057341668">"Dijeli koristeći"</string>
+ <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Dijeli koristeći %1$s"</string>
+ <string name="whichSendApplicationLabel" msgid="4579076294675975354">"Dijeli"</string>
<string name="whichSendToApplication" msgid="8272422260066642057">"Pošalji koristeći"</string>
<string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Pošalji koristeći %1$s"</string>
<string name="whichSendToApplicationLabel" msgid="8878962419005813500">"Pošalji"</string>
@@ -1073,6 +1075,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ponovo omogućite ovu opciju u meniju Postavke sistema > Aplikacije > Preuzete aplikacije."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava trenutnu postavku veličine ekrana i može se ponašati neočekivano."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Uvijek prikaži"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je napravljena za verziju operativnog sistema Android koja nije kompatibilna i može se ponašati neočekivano. Ažurirana verzija aplikacije može biti dostupna."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Uvijek prikaži"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Provjerite ima li ažuriranja"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) prekršila je vlastita StrictMode pravila."</string>
<string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> prekršio je vlastita StrictMode pravila."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Nadogradnja sistema Android u toku..."</string>
@@ -1140,10 +1145,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Prijava na mrežu"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nema pristup Internetu"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi nema pristup internetu"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Prebačeno na: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Kada na uređaju <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, koristi se <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata usluge."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Kada <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, uređaj koristi mrežu <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata usluge."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Prebačeno iz mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> u <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mrežu"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobilni podaci"</item>
@@ -1154,7 +1159,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nepoznata vrsta mreže"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Problem prilikom spajanja na Wi-Fi mrežu"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internet vezu."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ima lošu internetsku vezu."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Želite li dozvoliti povezivanje?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacija %1$s se želi povezati na Wi-Fi mrežu %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikacija"</string>
@@ -1286,7 +1291,7 @@
<string name="permlab_requestDeletePackages" msgid="1703686454657781242">"zatraži brisanje paketanja"</string>
<string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Omogućava aplikaciji da zatraži brisanje paketa."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"traži zanemarivanje optimizacije baterije"</string>
- <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Omogućava aplikaciji da traži dozvolu za zanemarivanje optimizacije baterije za tu aplikaciju."</string>
+ <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Omogućava aplikaciji da traži odobrenje za zanemarivanje optimizacije baterije za tu aplikaciju."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Dodirnite dvaput za kontrolu uvećanja"</string>
<string name="gadget_host_error_inflating" msgid="4882004314906466162">"Dodavanje vidžeta nije uspjelo."</string>
<string name="ime_action_go" msgid="8320845651737369027">"Započni"</string>
@@ -1298,12 +1303,12 @@
<string name="ime_action_default" msgid="2840921885558045721">"Izvrši"</string>
<string name="dial_number_using" msgid="5789176425167573586">"Biraj\nbroj <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="create_contact_using" msgid="4947405226788104538">"Napraviti kontakt\nkoristeći broj <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Sljedeće aplikacije zahtijevaju dozvolu za pristup vašem računu, sada i u budućnosti."</string>
+ <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Sljedeće aplikacije zahtijevaju odobrenje za pristup vašem računu, sada i u budućnosti."</string>
<string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Želite li dozvoliti taj zahtjev?"</string>
<string name="grant_permissions_header_text" msgid="6874497408201826708">"Zahtjev za pristup"</string>
<string name="allow" msgid="7225948811296386551">"Dozvoli"</string>
<string name="deny" msgid="2081879885755434506">"Odbijte"</string>
- <string name="permission_request_notification_title" msgid="6486759795926237907">"Upućen zahtjev za dozvolu"</string>
+ <string name="permission_request_notification_title" msgid="6486759795926237907">"Upućen zahtjev za odobrenje"</string>
<string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Upućen zahtjev za dozvolu\nza račun <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
<string name="forward_intent_to_owner" msgid="1207197447013960896">"Aplikaciju koristite van poslovnog profila"</string>
<string name="forward_intent_to_work" msgid="621480743856004612">"Aplikaciju koristite u poslovnom profilu"</string>
@@ -1350,7 +1355,7 @@
<string name="progress_erasing" product="default" msgid="6596988875507043042">"Brisanje SD kartice..."</string>
<string name="share" msgid="1778686618230011964">"Podijelite"</string>
<string name="find" msgid="4808270900322985960">"Pronađi"</string>
- <string name="websearch" msgid="4337157977400211589">"Internet pretraga"</string>
+ <string name="websearch" msgid="4337157977400211589">"Internet pretraživanje"</string>
<string name="find_next" msgid="5742124618942193978">"Nađi sljedeći"</string>
<string name="find_previous" msgid="2196723669388360506">"Nađi prethodni"</string>
<string name="gpsNotifTicker" msgid="5622683912616496172">"Korisnik <xliff:g id="NAME">%s</xliff:g> je poslao zahtjev za utvrđivanje lokacije"</string>
@@ -1394,7 +1399,7 @@
<string name="activitychooserview_choose_application" msgid="2125168057199941199">"Odaberite aplikaciju"</string>
<string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Aplikacija <xliff:g id="APPLICATION_NAME">%s</xliff:g> se ne može pokrenuti."</string>
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Podijeliti sa"</string>
- <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Podijeli koristeći aplikaciju <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Dijeli koristeći aplikaciju <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Klizni regulator. Dodirnite & držite."</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Prevucite za otključavanje ekrana."</string>
<string name="action_bar_home_description" msgid="5293600496601490216">"Vratite se na početnu stranicu"</string>
@@ -1521,6 +1526,10 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Kada je prečica uključena, pritiskom na oba dugmeta za podešavanje jačine zvuka u trajanju od 3 sekunde pokrenut će se funkcija za pristupačnost.\n\n Trenutna funkcija za pristupačnost je:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funkciju možete promijeniti ako odete u Postavke > Pristupačnost."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Isključi prečicu"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Koristi prečicu"</string>
+ <!-- no translation found for color_inversion_feature_name (4231186527799958644) -->
+ <skip />
+ <!-- no translation found for color_correction_feature_name (6779391426096954933) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečica za pristupačnost je uključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečica za pristupačnost je isključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Odaberite funkciju koja će se koristiti kada dodirnete dugme Pristupačnost:"</string>
@@ -1661,7 +1670,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Instalirao je vaš administrator"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Ažurirao je vaš administrator"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Izbrisao je vaš administrator"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Da bi se produžilo trajanje baterije, opcija za uštedu baterije minimizira rad uređaja i ograničava vibraciju, usluge lokacije i većinu prijenosa podataka u pozadini. E-pošta, poruke i druge aplikacije koje se oslanjaju na sinhronizaciju ne mogu se ažurirati dok ih ne otvorite.\n\nUšteda baterije se automatski isključuje prilikom punjenja uređaja."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Za produženje trajanja baterije, Ušteda baterije svodi rad uređaja na najmanju moguću mjeru i ograničava vibriranje, usluge lokacije i većinu prijenosa podataka u pozadini. Aplikacije za e-poštu, razmjenu poruka i druge aplikacije koje se oslanjaju na sinhronizaciju ne mogu se ažurirati dok ih ne otvorite.\n\nUšteda baterije se automatski isključuje prilikom punjenja uređaja."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjio prijenos podataka, usluga Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali se to može desiti rjeđe. To može značiti, naprimjer, da se slike ne prikazuju sve dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Uključiti Uštedu podataka?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Uključi"</string>
@@ -1716,6 +1725,8 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Radni dan uvečer"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Vikend"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Događaj"</string>
+ <!-- no translation found for zen_mode_default_every_night_name (3012363838882944175) -->
+ <skip />
<string name="muted_by" msgid="6147073845094180001">"Ton isključila aplikacija <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Postoji problem u vašem uređaju i može biti nestabilan dok ga ne vratite na fabričke postavke."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Postoji problem u vašem uređaju. Za više informacija obratite se proizvođaču."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 8b07393..1799069 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -79,8 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Sense servei de veu/emergència"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"La xarxa mòbil de la teva ubicació temporalment no ofereix aquest servei"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"No es pot accedir a la xarxa"</string>
- <!-- no translation found for NetworkPreferenceSwitchSummary (7056776609127756440) -->
- <skip />
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Per millorar la recepció, prova de canviar el tipus de xarxa a Configuració > Xarxa i Internet > Xarxes mòbils > Tipus de xarxa preferit."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"La funció Trucades per Wi Fi està activada"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Per poder fer trucades d\'emergència, cal tenir connexió a una xarxa mòbil."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Alertes"</string>
@@ -1052,12 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Torna a activar-ho a Configuració del sistema > Aplicacions > Baixades."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet la mida de pantalla actual i és possible que funcioni de manera inesperada."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostra sempre"</string>
- <!-- no translation found for unsupported_compile_sdk_message (5030433583092006591) -->
- <skip />
- <!-- no translation found for unsupported_compile_sdk_show (2681877855260970231) -->
- <skip />
- <!-- no translation found for unsupported_compile_sdk_check_update (3312723623323216101) -->
- <skip />
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> es va crear per a una versió incompatible del sistema operatiu Android i pot funcionar de manera inesperada. És possible que hi hagi disponible una versió actualitzada de l\'aplicació."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Mostra sempre"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Cerca actualitzacions"</string>
<string name="smv_application" msgid="3307209192155442829">"L\'aplicació <xliff:g id="APPLICATION">%1$s</xliff:g>(procés <xliff:g id="PROCESS">%2$s</xliff:g>) ha incomplert la seva política autoimposada de mode estricte."</string>
<string name="smv_process" msgid="5120397012047462446">"El procés <xliff:g id="PROCESS">%1$s</xliff:g> ha incomplert la seva política de mode estricte."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android s\'està actualitzant..."</string>
@@ -1123,12 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Inicia la sessió a la xarxa"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <!-- no translation found for wifi_no_internet (8938267198124654938) -->
- <skip />
+ <string name="wifi_no_internet" msgid="8938267198124654938">"La Wi-Fi no té accés a Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca per veure les opcions"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Actualment en ús: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <!-- no translation found for network_switch_metered_detail (775163331794506615) -->
- <skip />
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"El dispositiu utilitza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> en cas que <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tingui accés a Internet. És possible que s\'hi apliquin càrrecs."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Abans es feia servir la xarxa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>; ara s\'utilitza <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"dades mòbils"</item>
@@ -1643,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Instal·lat per l\'administrador"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Actualitzat per l\'administrador"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Suprimit per l\'administrador"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Per tal d\'augmentar la durada de la bateria, la funció d\'estalvi de bateria redueix el rendiment del dispositiu i en limita la vibració, els serveis d\'ubicació i la majoria de dades en segon pla. És possible que el correu electrònic, la missatgeria i la resta d\'aplicacions que se sincronitzen amb freqüència no s\'actualitzin llevat que les obris.\n\nL\'estalvi de bateria es desactiva automàticament mentre el dispositiu s\'està carregant."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Per tal d\'augmentar la durada de la bateria, la funció Estalvi de bateria redueix el rendiment del dispositiu i en limita la vibració, els serveis d\'ubicació i la majoria de dades en segon pla. És possible que el correu electrònic, la missatgeria i la resta d\'aplicacions que se sincronitzen amb freqüència no s\'actualitzin llevat que les obris.\n\nLa funció Estalvi de bateria es desactiva automàticament mentre el dispositiu s\'està carregant."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Per reduir l\'ús de dades, la funció Economitzador de dades evita que determinades aplicacions enviïn o rebin dades en segon pla. L\'aplicació que estiguis fent servir podrà accedir a dades, però potser ho farà menys sovint. Això vol dir, per exemple, que les imatges no es mostraran fins que no les toquis."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Activar Economitzador de dades?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Activa"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index a7021e9..ee47b43 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -81,7 +81,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Hlasová ani tísňová volání nejsou k dispozici"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Mobilní síť ve vaší oblasti tuto službu dočasně nenabízí"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"K síti se nelze připojit"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Chcete-li zlepšit příjem, zkuste změnit vybraný typ sítě v Nastavení > Síť a internet > Mobilní sítě > Preferovaný typ sítě."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Chcete-li zlepšit příjem, zkuste změnit vybraný typ sítě v Nastavení > Síť a internet > Mobilní sítě > Preferovaný typ sítě."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Volání přes Wi-Fi je aktivní"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Tísňová volání vyžadují mobilní síť."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Upozornění"</string>
@@ -1091,6 +1091,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Tento režim znovu povolíte v sekci Nastavení systému > Aplikace > Stažené."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> aktuální nastavení velikosti zobrazení nepodporuje a může se chovat neočekávaně."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Vždy zobrazovat"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> byla vytvořena nekompatibilní systému Android a může se chovat neočekávaně. K dispozici může být aktualizovaná verze aplikace."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Vždy zobrazovat"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Zkontrolovat aktualizace"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikace <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) porušila své vlastní vynucené zásady StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> porušil své vlastní vynucené zásady StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android se upgraduje..."</string>
@@ -1160,10 +1163,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Přihlásit se k síti"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nemá přístup k internetu"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi nemá přístup k internetu"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Klepnutím zobrazíte možnosti"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Přechod na síť <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Když síť <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nebude mít přístup k internetu, zařízení použije síť <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Mohou být účtovány poplatky."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Když síť <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nebude mít přístup k internetu, zařízení použije síť <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Mohou být účtovány poplatky."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Přechod ze sítě <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na síť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobilní data"</item>
@@ -1174,7 +1177,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"neznámý typ sítě"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Připojení k síti Wi-Fi se nezdařilo"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" má pomalé připojení k internetu."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" má pomalé připojení k internetu."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Povolit připojení?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikace %1$s se chce připojit k síti Wi-Fi %2$s."</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikace"</string>
@@ -1676,7 +1679,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. <xliff:g id="LABEL">%1$s</xliff:g> do práce"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. <xliff:g id="LABEL">%1$s</xliff:g> do práce"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Chcete-li tuto obrazovku uvolnit, podržte tlačítka Zpět a Přehled"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Tuto aplikaci nelze odepnout"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Obrazovka připnuta"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Obrazovka uvolněna"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Před uvolněním požádat o PIN"</string>
@@ -1685,7 +1687,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Nainstalováno administrátorem"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Aktualizováno administrátorem"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Smazáno administrátorem"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Spořič baterie prodlužuje výdrž baterie tím, že snižuje výkon zařízení a omezuje vibrace, služby určování polohy a většinu dat na pozadí. E-mail, aplikace pro zasílání zpráv a další aplikace, které používají synchronizaci, se nemusejí aktualizovat, dokud je neotevřete.\n\nPři nabíjení zařízení se spořič baterie automaticky vypne."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Spořič baterie za účelem prodloužení výdrže baterie snižuje výkon zařízení a omezuje vibrace, služby určování polohy a většinu dat na pozadí. E-mail, aplikace pro zasílání zpráv a další aplikace, které používají synchronizaci, se nemusejí aktualizovat, dokud je neotevřete.\n\nPři nabíjení zařízení se spořič baterie automaticky vypne."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Spořič dat z důvodu snížení využití dat některým aplikacím brání v odesílání nebo příjmu dat na pozadí. Aplikace, kterou právě používáte, data přenášet může, ale může tak činit méně často. V důsledku toho se například obrázky nemusejí zobrazit, dokud na ně neklepnete."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Chcete zapnout Spořič dat?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Zapnout"</string>
@@ -1852,14 +1854,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test nouzových zpráv"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Odpovědět"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM karta není povolena pro hlasovou komunikaci"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM karta není poskytována pro hlasovou komunikaci"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM karta není povolena pro hlasovou komunikaci"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefon není povolen pro hlasovou komunikaci"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Vyskakovací okno"</string>
<string name="slice_more_content" msgid="8504342889413274608">"a ještě <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Tato zkratka vyžaduje nejnovější verzi aplikace"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 5b0edbe..0a3892f 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Ingen tale- og nødtjenester"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Tilbydes i øjeblikket ikke af mobilnetværket på din placering"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Der er ingen forbindelse til netværket"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Hvis du vil forbedre signalet, kan du prøve at ændre den valgte netværkstype i Indstillinger > Netværk og internet > Mobilnetværk > Foretrukken netværkstype."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Hvis du vil forbedre signalet, kan du prøve at ændre den valgte netværkstype i Indstillinger > Netværk og internet > Mobilnetværk > Foretrukken netværkstype."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi-opkald er aktiveret"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Nødopkald kræver adgang til et mobilnetværk."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Underretninger"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktivér dette igen i Systemindstillinger > Apps > Downloadet."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> understøtter ikke den aktuelle indstilling for visningsstørrelse og vil muligvis ikke fungere som forventet."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Vis altid"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> er lavet til en inkompatibel version af Android OS, og det er ikke sikkert, den fungerer som forventet. Der findes muligvis en opdateret version af appen."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Vis altid"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Søg efter opdatering"</string>
<string name="smv_application" msgid="3307209192155442829">"Appen <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) har overtrådt sin egen StrictMode-politik."</string>
<string name="smv_process" msgid="5120397012047462446">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> har overtrådt sin egen StrictMode-politik."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android opgraderes..."</string>
@@ -1095,7 +1098,7 @@
<string name="ringtone_silent" msgid="7937634392408977062">"Ingen"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Ringetoner"</string>
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarmlyde"</string>
- <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Meddelelseslyde"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Underretningslyde"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"Ukendt"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="one">Tilgængelige Wi-Fi-netværk</item>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Log ind på netværk"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi har ingen internetadgang"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi-netværket har ikke internetadgang"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tryk for at se valgmuligheder"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Der blev skiftet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Enheden benytter <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, når <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ikke har adgang til internettet. Der opkræves muligvis gebyr."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Enheden benytter <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, når der ikke er internetadgang via <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Der opkræves muligvis betaling."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Der blev skiftet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobildata"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"en ukendt netværkstype"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kunne ikke oprette forbindelse til Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dårlig internetforbindelse."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" har en dårlig internetforbindelse."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vil du tillade denne forbindelse?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Applikationen %1$s vil gerne have forbindelse til Wi-Fi-netværk %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"En applikation"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. <xliff:g id="LABEL">%1$s</xliff:g> til arbejde"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. <xliff:g id="LABEL">%1$s</xliff:g> til arbejde"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Hvis du vil frigøre dette skærmbillede, skal du trykke på knapperne Tilbage og Oversigt og holde fingrene nede"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Denne app kan ikke frigøres"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Skærmen blev fastgjort"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Skærmen blev frigjort"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Bed om pinkode inden frigørelse"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Installeret af din administrator"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Opdateret af din administrator"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Slettet af din administrator"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Batterisparefunktionen hjælper med at forlænge batteriets levetid ved at reducere enhedens ydeevne og begrænse vibration, placeringstjenester og det meste baggrundsdata. E-mail, beskedfunktioner og andre apps, der benytter synkronisering, opdateres muligvis ikke, medmindre du åbner dem.\n\nBatterisparefunktionen deaktiveres automatisk, når enheden oplader."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Batterisparefunktionen hjælper med at forlænge batteritiden ved at reducere enhedens ydeevne og begrænse vibration, placeringstjenester og det meste baggrundsdata. Mail, beskedfunktioner og andre apps, der benytter synkronisering, opdateres muligvis ikke, medmindre du åbner dem.\n\nBatterisparefunktionen deaktiveres automatisk, når enheden oplader."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Datasparefunktionen forhindrer nogle apps i at sende eller modtage data i baggrunden for at reducere dataforbruget. En app, der er i brug, kan få adgang til data, men gør det måske ikke så ofte. Dette kan f.eks. betyde, at billeder ikke vises, før du trykker på dem."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Vil du slå Datasparefunktion til?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Slå til"</string>
@@ -1648,7 +1650,7 @@
<item quantity="other">I %1$d min. (indtil kl. <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
</plurals>
<plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
- <item quantity="one">I %1$d timer (indtil <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="one">I %1$d time (indtil <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="other">I %1$d timer (indtil <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
</plurals>
<plurals name="zen_mode_duration_hours_summary_short" formatted="false" msgid="4787552595253082371">
@@ -1664,7 +1666,7 @@
<item quantity="other">I %d min.</item>
</plurals>
<plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
- <item quantity="one">I %d timer</item>
+ <item quantity="one">I %d time</item>
<item quantity="other">I %d timer</item>
</plurals>
<plurals name="zen_mode_duration_hours_short" formatted="false" msgid="6748277774662434217">
@@ -1782,18 +1784,14 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test af nødbeskeder"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Svar"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM-kort er ikke tilladt for tale"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM-kort er ikke aktiveret for tale"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM-kort er ikke tilladt for tale"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefon er ikke tilladt for tale"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Pop op-vindue"</string>
<string name="slice_more_content" msgid="8504342889413274608">"<xliff:g id="NUMBER">%1$d</xliff:g> mere"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Denne genvej kræver den nyeste app"</string>
- <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Genvejen kunne ikke gendannes, da appen ikke understøtter sikkerhedskopiering og gendannelse"</string>
+ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Genvejen kunne ikke gendannes, da appen ikke understøtter backup og gendannelse"</string>
<string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Genvejen kunne ikke gendannes på grund af uoverensstemmelse i appsignatur"</string>
<string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Genvejen kunne ikke gendannes"</string>
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 0cff7dd..c85c268 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Keine Anrufe/Notrufe"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Derzeit nicht im Mobilfunknetz in deiner Region verfügbar"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Netzwerk nicht erreichbar"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Der Empfang lässt sich möglicherweise verbessern, indem du unter \"Einstellungen\" > \"Netzwerk\" & \"Internet\" > \"Mobilfunknetze\" > \"Bevorzugter Netzwerktyp\" einen anderen Typ auswählst."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Der Empfang lässt sich möglicherweise verbessern, indem du unter \"Einstellungen\" > \"Netzwerk\"& \"Internet\" > \"Mobilfunknetze\" > \"Bevorzugter Netzwerktyp\" einen anderen Typ auswählst."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"\"Anrufe über WLAN\" ist aktiv"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Für Notrufe ist ein Mobilfunknetz erforderlich."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Warnmeldungen"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Eine erneute Aktivierung ist in den Systemeinstellungen unter \"Apps > Heruntergeladen\" möglich."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> unterstützt nicht die aktuelle Einstellung für die Anzeigegröße, sodass ein unerwartetes Verhalten auftreten kann."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Immer anzeigen"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> ist mit der Version deines Android-Betriebssystems nicht kompatibel, wodurch ein unerwartetes Verhalten auftreten kann. Möglicherweise ist eine aktualisierte Version der App verfügbar."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Immer anzeigen"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Auf Updates überprüfen"</string>
<string name="smv_application" msgid="3307209192155442829">"Die App <xliff:g id="APPLICATION">%1$s</xliff:g> (Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) hat gegen deine selbsterzwungene StrictMode-Richtlinie verstoßen."</string>
<string name="smv_process" msgid="5120397012047462446">"Der Prozess <xliff:g id="PROCESS">%1$s</xliff:g> hat gegen seine selbsterzwungene StrictMode-Richtlinie verstoßen."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android wird aktualisiert..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Im Netzwerk anmelden"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"WLAN hat keinen Internetzugriff"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"WLAN hat keinen Internetzugriff"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Für Optionen tippen"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Zu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> gewechselt"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Auf dem Gerät wird \"<xliff:g id="NEW_NETWORK">%1$s</xliff:g>\" verwendet, wenn über \"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>\" kein Internet verfügbar ist. Eventuell fallen Gebühren an."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Auf dem Gerät werden <xliff:g id="NEW_NETWORK">%1$s</xliff:g> genutzt, wenn über <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> kein Internet verfügbar ist. Eventuell fallen Gebühren an."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Von \"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>\" zu \"<xliff:g id="NEW_NETWORK">%2$s</xliff:g>\" gewechselt"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"Mobile Daten"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ein unbekannter Netzwerktyp"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Es konnte keine WLAN-Verbindung hergestellt werden."</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" hat eine schlechte Internetverbindung."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" hat eine schlechte Internetverbindung."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Verbindung zulassen?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Die App \"%1$s\" möchte eine Verbindung zum WLAN %2$s herstellen."</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Eine App"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. <xliff:g id="LABEL">%1$s</xliff:g> (geschäftlich)"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. <xliff:g id="LABEL">%1$s</xliff:g> (geschäftlich)"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Um diesen Bildschirm loszulösen, berühre und halte gleichzeitig \"Zurück\" und \"Übersicht\""</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Diese App kann nicht losgelöst werden"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Bildschirm fixiert"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Bildschirm gelöst"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vor dem Beenden nach PIN fragen"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Von deinem Administrator installiert"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Von deinem Administrator aktualisiert"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Von deinem Administrator gelöscht"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Der Energiesparmodus schont den Akku, indem er die Leistung des Geräts reduziert und die Vibrationsfunktion, Standortdienste sowie die meisten Hintergrunddatenaktivitäten einschränkt. E-Mail, SMS/MMS und andere Apps, die auf deinem Gerät synchronisiert werden, werden möglicherweise erst nach dem Öffnen aktualisiert.\n\nDer Energiesparmodus wird automatisch deaktiviert, wenn dein Gerät aufgeladen wird."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Der Energiesparmodus schont den Akku, indem er die Leistung des Geräts reduziert und die Vibrationsfunktion, Standortdienste sowie die meisten Hintergrunddatenaktivitäten einschränkt. E-Mail, SMS/MMS und andere Apps, die auf deinem Gerät synchronisiert werden, werden möglicherweise nur aktualisiert, wenn du sie öffnest.\n\nDer Energiesparmodus wird automatisch deaktiviert, wenn dein Gerät aufgeladen wird."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Mit dem Datensparmodus wird die Datennutzung verringert, indem verhindert wird, dass im Hintergrund Daten von Apps gesendet oder empfangen werden. Datenzugriffe sind mit einer aktiven App zwar möglich, erfolgen aber seltener. Als Folge davon könnten Bilder beispielsweise erst dann sichtbar werden, wenn sie angetippt werden."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Datensparmodus aktivieren?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Aktivieren"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test der Notfallwarnungen"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Antworten"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM unterstützt die Sprachfunktion nicht"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM nicht für Sprachfunktion eingerichtet"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM unterstützt die Sprachfunktion nicht"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Smartphone unterstützt Sprachfunktion nicht"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Pop-up-Fenster"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Für diese Verknüpfung ist die aktuelle App-Version erforderlich"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 9619737..1fcaf97 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Δεν υπάρχει φωνητική υπηρεσία/υπηρεσία έκτακτης ανάγκης"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Δεν προσφέρεται προσωρινά από το δίκτυο κινητής τηλεφωνίας στην τοποθεσία σας"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Δεν είναι δυνατή η σύνδεση στο δίκτυο"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Για να βελτιώσετε τη λήψη, δοκιμάστε να αλλάξετε τον επιλεγμένο τύπο από τις Ρυθμίσεις > Δίκτυο και διαδίκτυο > Δίκτυα κινητής τηλεφωνίας > Προτιμώμενος τύπος δικτύου."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Για να βελτιώσετε τη λήψη, δοκιμάστε να αλλάξετε τον επιλεγμένο τύπο από τις Ρυθμίσεις > Δίκτυο και διαδίκτυο > Δίκτυα κινητής τηλεφωνίας > Προτιμώμενος τύπος δικτύου."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Η κλήση Wi‑Fi είναι ενεργή"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Για κλήσεις έκτακτης ανάγκης, απαιτείται δίκτυο κινητής τηλεφωνίας."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Ειδοποιήσεις"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ενεργοποιήστε το ξανά στις Ρυθμίσεις συστημάτων > Εφαρμογές > Ληφθείσες."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν υποστηρίζει την τρέχουσα ρύθμιση Μεγέθους οθόνης και ενδέχεται να παρουσιάζει μη αναμενόμενη συμπεριφορά."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Να εμφανίζεται πάντα"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δημιουργήθηκε για μια μη συμβατή έκδοση του λειτουργικού συστήματος Android και μπορεί να έχει μη αναμενόμενη συμπεριφορά. Μπορεί να υπάρχει ενημερωμένη έκδοση της εφαρμογής."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Να εμφανίζεται πάντα"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Έλεγχος για ενημέρωση"</string>
<string name="smv_application" msgid="3307209192155442829">"Η εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> (διεργασία <xliff:g id="PROCESS">%2$s</xliff:g>) παραβίασε την αυτοεπιβαλλόμενη πολιτική StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Η διεργασία <xliff:g id="PROCESS">%1$s</xliff:g> παραβίασε την αυτοεπιβαλόμενη πολιτική StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Το Android αναβαθμίζεται..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Σύνδεση στο δίκτυο"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Το δίκτυο Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Το Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Πατήστε για να δείτε τις επιλογές"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Μετάβαση σε δίκτυο <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Η συσκευή χρησιμοποιεί το δίκτυο <xliff:g id="NEW_NETWORK">%1$s</xliff:g> όταν το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> δεν έχει πρόσβαση στο διαδίκτυο. Ενδέχεται να ισχύουν χρεώσεις."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Η συσκευή χρησιμοποιεί το δίκτυο <xliff:g id="NEW_NETWORK">%1$s</xliff:g> όταν το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> δεν έχει πρόσβαση στο διαδίκτυο. Μπορεί να ισχύουν χρεώσεις."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Μετάβαση από το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> στο δίκτυο <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"δεδομένα κινητής τηλεφωνίας"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"άγνωστος τύπος δικτύου"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Δεν είναι δυνατή η σύνδεση στο Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" έχει κακή σύνδεση στο Διαδίκτυο."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" έχει κακή σύνδεση Διαδικτύου."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Να επιτρέπεται η σύνδεση;"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Η εφαρμογή %1$s θα ήθελε να συνδεθεί με το δίκτυο WiFi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Μια εφαρμογή"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> εργασίας 2"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> εργασίας 3"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Για να ξεκαρφιτσώσετε αυτήν την οθόνη, αγγίξτε παρατεταμένα τα κουμπιά \"Πίσω\" και \"Επισκόπηση\""</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Το ξεκαρφίτσωμα αυτής της εφαρμογής δεν είναι δυνατό"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Η οθόνη καρφιτσώθηκε"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Η οθόνη ξεκαρφιτσώθηκε"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Να γίνεται ερώτηση για το PIN, πριν από το ξεκαρφίτσωμα"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Εγκαταστάθηκε από τον διαχειριστή σας"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Ενημερώθηκε από τον διαχειριστή σας"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Διαγράφηκε από τον διαχειριστή σας"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Προκειμένου να βελτιώσει τη διάρκεια ζωής της μπαταρίας σας, η Εξοικονόμηση μπαταρίας μειώνει την απόδοση της συσκευής σας και περιορίζει λειτουργίες όπως η δόνηση, οι υπηρεσίες τοποθεσίας και τα περισσότερα δεδομένα παρασκηνίου. Το ηλεκτρονικό ταχυδρομείο, η ανταλλαγή μηνυμάτων και άλλες εφαρμογές που βασίζονται στο συγχρονισμό ενδέχεται να μην ενημερώνονται μέχρι να τις ανοίξετε.\n\nΗ Εξοικονόμηση μπαταρίας απενεργοποιείται αυτόματα όταν η συσκευή σας φορτίζει."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Προκειμένου να βελτιώσει τη διάρκεια ζωής της μπαταρίας σας, η Εξοικονόμηση μπαταρίας μειώνει την απόδοση της συσκευής σας και περιορίζει λειτουργίες όπως η δόνηση, οι υπηρεσίες τοποθεσίας και τα περισσότερα δεδομένα παρασκηνίου. Το ηλεκτρονικό ταχυδρομείο, η ανταλλαγή μηνυμάτων και άλλες εφαρμογές που βασίζονται στον συγχρονισμό μπορεί να μην ενημερώνονται έως ότου τις ανοίξετε.\n\nΗ Εξοικονόμηση μπαταρίας απενεργοποιείται αυτόματα κατά τη διάρκεια της φόρτισης της συσκευής σας."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Προκειμένου να μειωθεί η χρήση δεδομένων, η Εξοικονόμηση δεδομένων αποτρέπει την αποστολή ή λήψη δεδομένων από ορισμένες εφαρμογές στο παρασκήνιο. Μια εφαρμογή που χρησιμοποιείτε αυτήν τη στιγμή μπορεί να χρησιμοποιήσει δεδομένα αλλά με μικρότερη συχνότητα. Για παράδειγμα, οι εικόνες μπορεί να μην εμφανίζονται μέχρι να τις πατήσετε."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Ενεργ.Εξοικονόμησης δεδομένων;"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Ενεργοποίηση"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Δοκιμαστικό μήνυμα έκτακτης ανάγκης"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Απάντηση"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"Δεν επιτρέπεται η χρήση της κάρτας SIM για φωνητικές εντολές"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"Δεν παρέχεται κάρτα SIM για φωνητικές εντολές"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"Δεν επιτρέπεται η χρήση της κάρτας SIM για φωνητικές εντολές"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Δεν επιτρέπεται η χρήση του τηλεφώνου για φωνητικές εντολές"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Αναδυόμενο παράθυρο"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Αυτή η συντόμευση απαιτεί την πιο πρόσφατη έκδοση της εφαρμογής"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index e185683..a175e6c 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"No voice/emergency service"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Temporarily not offered by the mobile network at your location"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Can’t find network"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"To improve reception, try changing the type selected at Settings > Network & Internet > Mobile networks > Preferred network type."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"To improve reception, try changing the type selected at Settings > Network & Internet > Mobile networks > Preferred network type."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi calling is active"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Emergency calls require a mobile network."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Alerts"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings > Apps > Downloaded."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Always show"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> was built for an incompatible version of the Android OS and may behave unexpectedly. An updated version of the app may be available."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Always show"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Check for update"</string>
<string name="smv_application" msgid="3307209192155442829">"The app <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced Strict Mode policy."</string>
<string name="smv_process" msgid="5120397012047462446">"The process <xliff:g id="PROCESS">%1$s</xliff:g> has violated its self-enforced StrictMode policy."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android is upgrading…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Sign in to network"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi has no Internet access"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi has no Internet access"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobile data"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"an unknown network type"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" has a poor Internet connection."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" has a poor Internet connection."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Application %1$s would like to connect to Wi-Fi Network %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"An application"</string>
@@ -1634,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Installed by your admin"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Updated by your admin"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Deleted by your admin"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"To help improve battery life, Battery Saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery Saver turns off automatically when your device is charging."</string>
<string name="data_saver_description" msgid="6015391409098303235">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Turn on Data Saver?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Turn on"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index e185683..a175e6c 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"No voice/emergency service"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Temporarily not offered by the mobile network at your location"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Can’t find network"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"To improve reception, try changing the type selected at Settings > Network & Internet > Mobile networks > Preferred network type."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"To improve reception, try changing the type selected at Settings > Network & Internet > Mobile networks > Preferred network type."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi calling is active"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Emergency calls require a mobile network."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Alerts"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings > Apps > Downloaded."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Always show"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> was built for an incompatible version of the Android OS and may behave unexpectedly. An updated version of the app may be available."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Always show"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Check for update"</string>
<string name="smv_application" msgid="3307209192155442829">"The app <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced Strict Mode policy."</string>
<string name="smv_process" msgid="5120397012047462446">"The process <xliff:g id="PROCESS">%1$s</xliff:g> has violated its self-enforced StrictMode policy."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android is upgrading…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Sign in to network"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi has no Internet access"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi has no Internet access"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobile data"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"an unknown network type"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" has a poor Internet connection."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" has a poor Internet connection."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Application %1$s would like to connect to Wi-Fi Network %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"An application"</string>
@@ -1634,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Installed by your admin"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Updated by your admin"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Deleted by your admin"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"To help improve battery life, Battery Saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery Saver turns off automatically when your device is charging."</string>
<string name="data_saver_description" msgid="6015391409098303235">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Turn on Data Saver?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Turn on"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index e185683..a175e6c 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"No voice/emergency service"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Temporarily not offered by the mobile network at your location"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Can’t find network"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"To improve reception, try changing the type selected at Settings > Network & Internet > Mobile networks > Preferred network type."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"To improve reception, try changing the type selected at Settings > Network & Internet > Mobile networks > Preferred network type."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi calling is active"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Emergency calls require a mobile network."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Alerts"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings > Apps > Downloaded."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Always show"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> was built for an incompatible version of the Android OS and may behave unexpectedly. An updated version of the app may be available."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Always show"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Check for update"</string>
<string name="smv_application" msgid="3307209192155442829">"The app <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced Strict Mode policy."</string>
<string name="smv_process" msgid="5120397012047462446">"The process <xliff:g id="PROCESS">%1$s</xliff:g> has violated its self-enforced StrictMode policy."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android is upgrading…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Sign in to network"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi has no Internet access"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi has no Internet access"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobile data"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"an unknown network type"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" has a poor Internet connection."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" has a poor Internet connection."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Application %1$s would like to connect to Wi-Fi Network %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"An application"</string>
@@ -1634,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Installed by your admin"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Updated by your admin"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Deleted by your admin"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"To help improve battery life, Battery Saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery Saver turns off automatically when your device is charging."</string>
<string name="data_saver_description" msgid="6015391409098303235">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Turn on Data Saver?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Turn on"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index e185683..a175e6c 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"No voice/emergency service"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Temporarily not offered by the mobile network at your location"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Can’t find network"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"To improve reception, try changing the type selected at Settings > Network & Internet > Mobile networks > Preferred network type."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"To improve reception, try changing the type selected at Settings > Network & Internet > Mobile networks > Preferred network type."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi calling is active"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Emergency calls require a mobile network."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Alerts"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings > Apps > Downloaded."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Always show"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> was built for an incompatible version of the Android OS and may behave unexpectedly. An updated version of the app may be available."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Always show"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Check for update"</string>
<string name="smv_application" msgid="3307209192155442829">"The app <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced Strict Mode policy."</string>
<string name="smv_process" msgid="5120397012047462446">"The process <xliff:g id="PROCESS">%1$s</xliff:g> has violated its self-enforced StrictMode policy."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android is upgrading…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Sign in to network"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi has no Internet access"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi has no Internet access"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobile data"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"an unknown network type"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" has a poor Internet connection."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" has a poor Internet connection."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Application %1$s would like to connect to Wi-Fi Network %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"An application"</string>
@@ -1634,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Installed by your admin"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Updated by your admin"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Deleted by your admin"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"To help improve battery life, Battery Saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery Saver turns off automatically when your device is charging."</string>
<string name="data_saver_description" msgid="6015391409098303235">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Turn on Data Saver?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Turn on"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index b93e830..5635292 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1051,7 +1051,7 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings > Apps > Downloaded."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Always show"</string>
- <string name="unsupported_compile_sdk_message" msgid="5030433583092006591">"<xliff:g id="APP_NAME">%1$s</xliff:g> was built for preview version %2$s of the Android OS and may behave unexpectedly. An updated version of the app may be available."</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> was built for an incompatible version of the Android OS and may behave unexpectedly. An updated version of the app may be available."</string>
<string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Always show"</string>
<string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Check for update"</string>
<string name="smv_application" msgid="3307209192155442829">"The app <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced StrictMode policy."</string>
@@ -1637,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Installed by your admin"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Updated by your admin"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Deleted by your admin"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"To help improve battery life, Battery Saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery Saver turns off automatically when your device is charging."</string>
<string name="data_saver_description" msgid="6015391409098303235">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Turn on Data Saver?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Turn on"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 67dac60..22fe10d 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Sin servicio de voz/emergencia"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"La red móvil de tu ubicación no ofrece este servicio de forma temporal"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"No se puede establecer conexión con la red"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Para mejorar la recepción, cambia el tipo de red. Selecciona Configuración > Internet y red > Redes móviles > Tipo de red preferido."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Para mejorar la recepción, cambia el tipo de red. Selecciona Configuración > Internet y red > Redes móviles > Tipo de red preferido."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Las llamadas con Wi-Fi están activadas"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Las llamadas de emergencia requieren una red móvil."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Alertas"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Volver a activar Configuración del sistema > Aplicaciones > Descargas"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> no es compatible con la configuración del tamaño de pantalla actual. Es posible que no se comporte de manera correcta."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar siempre"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Se diseñó <xliff:g id="APP_NAME">%1$s</xliff:g> para una versión no compatible del SO Android. Es posible que dicha app funcione de forma inesperada y que ya haya una versión actualizada disponible."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Mostrar siempre"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Buscar actualización"</string>
<string name="smv_application" msgid="3307209192155442829">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha infringido su política StrictMode de aplicación automática."</string>
<string name="smv_process" msgid="5120397012047462446">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> ha violado su política StrictMode autoimpuesta."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android se está actualizando..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Acceder a la red"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"La red Wi-Fi no tiene acceso a Internet"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"La red Wi-Fi no tiene acceso a Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Presiona para ver opciones"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Se cambió a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"El dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"El dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Se cambió de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"Datos móviles"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un tipo de red desconocido"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No se pudo conectar a la red Wi-Fi."</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tiene una mala conexión a Internet."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" tiene una mala conexión a Internet."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"¿Permitir la conexión?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"La aplicación %1$s quiere conectarse a la red Wi-Fi %2$s."</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Una aplicación"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo 2"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo 3"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Para dejar de fijar esta pantalla, mantén presionados los botones Atrás y Recientes"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"No se puede dejar de fijar esta app"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fija"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Pantalla no fija"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar PIN para quitar fijación"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Tu administrador instaló este paquete"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Tu administrador actualizó este paquete"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Tu administrador borró este paquete"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Para mejorar la duración de la batería, la función de ahorro de batería reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayoría de los datos en segundo plano. Es posible que no puedan actualizarse el correo electrónico, la mensajería y otras aplicaciones que se basan en la sincronización, a menos que los abras.\n\nEl ahorro de batería se desactiva de forma automática cuando el dispositivo se está cargando."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Para mejorar la duración de la batería, el Ahorro de batería reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayoría de los datos en segundo plano. Es posible que no se puedan actualizar el correo electrónico, los mensajes y otras apps que se basan en la sincronización, a menos que los abras.\n\nEl Ahorro de batería se desactiva automáticamente cuando el dispositivo se está cargando."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Para reducir el uso de datos, \"Reducir datos\" evita que algunas apps envíen y reciban datos en segundo plano. La app que estés usando podrá acceder a los datos, pero con menor frecuencia. De esta forma, por ejemplo, las imágenes no se mostrarán hasta que las presiones."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"¿Activar Ahorro de datos?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Activar"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Prueba de mensajes de emergencia"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Responder"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"La SIM no admite acciones de voz"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"No se brindó una SIM para las acciones de voz"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"La SIM no admite acciones de voz"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"El teléfono no admite acciones de voz"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Ventana emergente"</string>
<string name="slice_more_content" msgid="8504342889413274608">"<xliff:g id="NUMBER">%1$d</xliff:g> más"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Este acceso directo requiere la app más reciente"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index dd26fe0..d9e3920 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Sin servicio de emergencia ni de voz"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"La red móvil disponible en tu ubicación no ofrece esta opción de forma temporal"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"No se puede establecer conexión con la red"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Para mejorar la recepción, prueba a cambiar el tipo seleccionado en Ajustes > Red e Internet > Redes móviles > Tipo de red preferido."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Para mejorar la recepción, prueba a cambiar el tipo seleccionado en Ajustes > Red e Internet > Redes móviles > Tipo de red preferido."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"La llamada por Wi‑Fi está activada"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Necesitas conectarte a una red móvil para hacer llamadas de emergencia."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Alertas"</string>
@@ -193,7 +193,7 @@
<string name="reboot_to_update_prepare" msgid="6305853831955310890">"Preparando para actualizar…"</string>
<string name="reboot_to_update_package" msgid="3871302324500927291">"Procesando paquete de actualización…"</string>
<string name="reboot_to_update_reboot" msgid="6428441000951565185">"Reiniciando…"</string>
- <string name="reboot_to_reset_title" msgid="4142355915340627490">"Restablecer datos de fábrica"</string>
+ <string name="reboot_to_reset_title" msgid="4142355915340627490">"Restablecer estado de fábrica"</string>
<string name="reboot_to_reset_message" msgid="2432077491101416345">"Reiniciando…"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Apagando..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"El tablet se apagará."</string>
@@ -564,9 +564,9 @@
<string name="policylab_forceLock" msgid="2274085384704248431">"Bloquear la pantalla"</string>
<string name="policydesc_forceLock" msgid="1141797588403827138">"Controlar cómo y cuándo se bloquea la pantalla"</string>
<string name="policylab_wipeData" msgid="3910545446758639713">"Borrar todos los datos"</string>
- <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Borrar los datos del tablet sin avisar restableciendo datos de fábrica"</string>
+ <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Borrar los datos del tablet sin avisar restableciendo el estado de fábrica"</string>
<string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Borra los datos de la TV sin advertencia previa restableciendo la TV a los valores predeterminados de fábrica."</string>
- <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Borrar los datos del teléfono sin avisar restableciendo datos de fábrica"</string>
+ <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Borrar los datos del teléfono sin avisar restableciendo el estado de fábrica"</string>
<string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Borrar datos del usuario"</string>
<string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Borra los datos del usuario en este tablet sin avisar."</string>
<string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Borra los datos del usuario en esta TV sin avisar."</string>
@@ -744,12 +744,12 @@
<string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, deberás usar tus credenciales de acceso de Google para desbloquear el tablet.\n\n Inténtalo de nuevo dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Has dibujado el patrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, deberás desbloquear la TV iniciando sesión en Google.\n\n Vuelve a intentarlo dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, deberás usar tus credenciales de acceso de Google para desbloquear el teléfono.\n\n Inténtalo de nuevo dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
- <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Has intentado desbloquear el tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> veces, pero no lo has conseguido. Si fallas <xliff:g id="NUMBER_1">%2$d</xliff:g> veces más, se restablecerán los datos de fábrica y se perderán todos los datos del usuario."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Has intentado desbloquear el tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> veces, pero no lo has conseguido. Si fallas <xliff:g id="NUMBER_1">%2$d</xliff:g> veces más, se restablecerá el estado de fábrica y se perderán todos los datos del usuario."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Has intentado desbloquear la TV incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, la TV se restablecerá a los valores predeterminados de fábrica y se perderán todos los datos del usuario."</string>
- <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Has intentado desbloquear el teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces, pero no lo has conseguido. Si fallas <xliff:g id="NUMBER_1">%2$d</xliff:g> veces más, se restablecerán los datos de fábrica y se perderán todos los datos del usuario."</string>
- <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Has intentado desbloquear el tablet <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo has conseguido. Se restablecerán los datos de fábrica del dispositivo."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Has intentado desbloquear el teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces, pero no lo has conseguido. Si fallas <xliff:g id="NUMBER_1">%2$d</xliff:g> veces más, se restablecerá el estado de fábrica y se perderán todos los datos del usuario."</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Has intentado desbloquear el tablet <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo has conseguido. Se restablecerá el estado de fábrica del dispositivo."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Has intentando desbloquear la TV incorrectamente <xliff:g id="NUMBER">%d</xliff:g> veces. La TV se restablecerá a los valores predeterminados de fábrica."</string>
- <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Has intentado desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo has conseguido. Se restablecerán los datos de fábrica del dispositivo."</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Has intentado desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo has conseguido. Se restablecerá el estado de fábrica del dispositivo."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Espera <xliff:g id="NUMBER">%d</xliff:g> segundos y vuelve a intentarlo."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"¿Has olvidado el patrón?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Desbloqueo de cuenta"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Para volver a habilitar esta opción, accede a Ajustes > Aplicaciones > Descargadas."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite el tamaño de pantalla actual y es posible que funcione de forma inesperada."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar siempre"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> se diseñó para una versión incompatible de Android OS y puede que funcione de forma inesperada. Es posible que haya una versión actualizada de la aplicación."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Mostrar siempre"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Comprobar actualizaciones"</string>
<string name="smv_application" msgid="3307209192155442829">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha infringido su política StrictMode autoaplicable."</string>
<string name="smv_process" msgid="5120397012047462446">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> ha infringido su política StrictMode autoaplicable."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Actualizando Android"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Iniciar sesión en la red"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi sin acceso a Internet"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"La red Wi-Fi no tiene acceso a Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca para ver opciones"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Se ha cambiado a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"El dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"El dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Se ha cambiado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"datos móviles"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tipo de red desconocido"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No se ha podido establecer conexión con la red Wi-Fi."</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tiene una conexión inestable a Internet."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" tiene una mala conexión a Internet."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"¿Permitir la conexión?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"La aplicación %1$s quiere establecer conexión con la red Wi-Fi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Una aplicación"</string>
@@ -1479,12 +1482,12 @@
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has introducido un código PIN incorrecto <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Has introducido una contraseña incorrecta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar tu patrón de desbloqueo. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Has intentado desbloquear el tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> veces, pero no lo has conseguido. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se restablecerán los datos de fábrica y se perderán todos los datos del usuario."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Has intentado desbloquear el tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> veces, pero no lo has conseguido. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se restablecerá el estado de fábrica y se perderán todos los datos del usuario."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"Has intentado desbloquear la TV incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, la TV se restablecerá a los valores predeterminados de fábrica y se perderán todos los datos del usuario."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Has intentado desbloquear el teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces, pero no lo has conseguido. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se restablecerán los datos de fábrica y se perderán todos los datos del usuario."</string>
- <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Has intentado desbloquear el tablet <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo has conseguido. Se restablecerán los datos de fábrica del dispositivo."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Has intentado desbloquear el teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces, pero no lo has conseguido. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se restablecerá el estado de fábrica y se perderán todos los datos del usuario."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Has intentado desbloquear el tablet <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo has conseguido. Se restablecerá el estado de fábrica del dispositivo."</string>
<string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"Has intentando desbloquear la TV incorrectamente <xliff:g id="NUMBER">%d</xliff:g> veces. La TV se restablecerá a los valores predeterminados de fábrica."</string>
- <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Has intentado desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo has conseguido. Se restablecerán los datos de fábrica del dispositivo."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Has intentado desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo has conseguido. Se restablecerá el estado de fábrica del dispositivo."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el tablet.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Has dibujado el patrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, deberás desbloquear la TV mediante una cuenta de correo electrónico.\n\n Vuelve a intentarlo dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el teléfono.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
@@ -1634,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Instalado por el administrador"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Actualizado por el administrador"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Eliminado por el administrador"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Para mejorar la duración de la batería, la función de ahorro de batería reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayor parte de los datos en segundo plano. Es posible que las aplicaciones que se sincronizan, como las de correo y mensajes, no se actualicen a menos que las abras.\n\nLa función de ahorro de batería se desactiva automáticamente cuando el dispositivo se está cargando."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Para mejorar la duración de la batería, la función Ahorro de batería reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayor parte de los datos en segundo plano. Es posible que las aplicaciones que se sincronizan, como las de correo y mensajes, no se actualicen a menos que las abras.\n\nLa función Ahorro de batería se desactiva automáticamente cuando el dispositivo se está cargando."</string>
<string name="data_saver_description" msgid="6015391409098303235">"El ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que permite reducir el uso de datos. Una aplicación activa podrá acceder a los datos, aunque con menos frecuencia. Esto significa que, por ejemplo, algunas imágenes no se muestren hasta que no las toques."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"¿Activar ahorro de datos?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Activar"</string>
@@ -1682,7 +1685,7 @@
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Fin de semana"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Evento"</string>
<string name="muted_by" msgid="6147073845094180001">"Silenciado por <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
- <string name="system_error_wipe_data" msgid="6608165524785354962">"Se ha producido un problema interno en el dispositivo y es posible que este no sea estable hasta que restablezcas los datos de fábrica."</string>
+ <string name="system_error_wipe_data" msgid="6608165524785354962">"Se ha producido un problema interno en el dispositivo y es posible que este no sea estable hasta que restablezcas el estado de fábrica."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Se ha producido un problema interno en el dispositivo. Ponte en contacto con el fabricante para obtener más información."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"La solicitud USSD se ha modificado para la solicitud DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"La solicitud USSD se ha modificado para la solicitud SS."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 27ceef2..7de0c3b 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Häälkõned/hädaabiteenus pole saadaval"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Teie asukoha mobiilsidevõrk seda teenust ajutiselt ei paku"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Võrguga ei saa ühendust"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Vastuvõtu parandamiseks muutke valitud tüüpi jaotises Seaded > Võrk ja Internet > Mobiilsidevõrgud > Eelistatud võrgutüüp."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Vastuvõtu parandamiseks muutke valitud tüüpi jaotises Seaded > Võrk ja Internet > Mobiilsidevõrgud > Eelistatud võrgutüüp."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"WiFi-kõned on aktiivsed"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Hädaabikõnede jaoks on vajalik mobiilsidevõrk."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Teatised"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Lubage see uuesti valikutes Süsteemiseaded > Rakendused > Allalaaditud."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> ei toeta praegust ekraani suuruse seadet ja võib ootamatult käituda."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Kuva alati"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> loodi Android OS-i ühildumatu versiooni jaoks ja võib käituda ootamatult. Saadaval võib olla rakenduse värskendatud versioon."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Kuva alati"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Otsi värskendust"</string>
<string name="smv_application" msgid="3307209192155442829">"Rakendus <xliff:g id="APPLICATION">%1$s</xliff:g> (protsess <xliff:g id="PROCESS">%2$s</xliff:g>) on rikkunud isekehtestatud StrictMode\'i eeskirju."</string>
<string name="smv_process" msgid="5120397012047462446">"Protsess <xliff:g id="PROCESS">%1$s</xliff:g> on rikkunud isejõustatud StrictMode\'i eeskirju."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android viiakse üle uuemale versioonile ..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Võrku sisselogimine"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"WiFi-l pole juurdepääsu Internetile"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"WiFi-võrgul pole juurdepääsu Internetile"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Puudutage valikute nägemiseks"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Lülitati võrgule <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Seade kasutab võrku <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, kui võrgul <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> puudub Interneti-ühendus. Rakenduda võivad tasud."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Seade kasutab võrku <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, kui võrgul <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> puudub juurdepääs Internetile. Rakenduda võivad tasud."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Lülitati võrgult <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> võrgule <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobiilne andmeside"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tundmatu võrgutüüp"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ei saanud WiFi-ga ühendust"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" on halb Interneti-ühendus."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" on halb Interneti-ühendus."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Kas lubada ühendus?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Rakendus %1$s soovib luua ühenduse WiFi-võrguga %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Rakendus"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. töö <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. töö <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Ekraani vabastamiseks puudutage pikalt nuppe Tagasi ja Ülevaade"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Seda rakendust ei saa vabastada"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Ekraan on kinnitatud"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Ekraan on vabastatud"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Enne vabastamist küsi PIN-koodi"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Administraator on selle installinud"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Administraator on seda värskendanud"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Administraator on selle kustutanud"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Aku kestuse parandamiseks vähendab akusäästja teie seadme toimivust ning piirab vibreerimist, asukohateenuseid ja suuremat osa taustaandmetest. E-posti, sõnumsidet ja muid sünkroonimisele tuginevaid rakendusi võidakse värskendada ainult siis, kui te need avate.\n\nAkusäästja lülitatakse seadme laadimise ajal automaatselt välja."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Aku tööea parandamiseks vähendab akusäästja teie seadme toimivust ning piirab vibratsiooni, asukohateenuseid ja suuremat osa taustaandmetest. E-posti, sõnumsidet ja muid sünkroonimisele tuginevaid rakendusi võidakse värskendada ainult siis, kui need avate.\n\nSeadme laadimise ajal lülitatakse akusäästja automaatselt välja."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Andmekasutuse vähendamiseks keelab andmeside mahu säästja mõne rakenduse puhul andmete taustal saatmise ja vastuvõtmise. Rakendus, mida praegu kasutate, pääseb andmesidele juurde, kuid võib seda teha väiksema sagedusega. Seetõttu võidakse näiteks kujutised kuvada alles siis, kui neid puudutate."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Lül. andmemahu säästja sisse?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Lülita sisse"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Hädaabisõnumite test"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Vasta"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM-kaarti ei lubata häälega kasutada"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM-kaart pole häälega kasutamiseks ettevalmistatud"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM-kaarti ei lubata häälega kasutada"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefoni ei lubata häälega kasutada"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Hüpikaken"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"See otsetee nõuab rakenduse uusimat versiooni"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index ae29264..e62a7f6 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Ez dago ahots- edo larrialdi-deien zerbitzurik"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Zauden tokiko sare mugikorrak ez du eskaintzen aukera hori une honetan"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Ezin da konektatu sarera"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Seinalea hobea izan dadin, aldatu sare mota Ezarpenak > Sareak eta Internet > Sare mugikorrak > Sare mota hobetsia atalean."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Seinalea hobea izan dadin, aldatu sare mota Ezarpenak > Sareak eta Internet > Sare mugikorrak > Sare mota hobetsia atalean."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi bidezko deiak aktibo daude"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Sare mugikorrera konektatuta egon behar da larrialdi-deiak egin ahal izateko."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Abisuak"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Gaitu hori berriro Sistemaren ezarpenak > Aplikazioak > Deskargatutakoak."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak ez du onartzen uneko pantailaren tamaina eta espero ez bezala joka lezake."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Erakutsi beti"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Android sistema eragilearen bertsio bateraezin baterako dago egina <xliff:g id="APP_NAME">%1$s</xliff:g>; beraz, espero ez bezala funtziona lezake. Baliteke aplikazioaren bertsio eguneratuago bat eskuragarri egotea."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Erakutsi beti"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Bilatu eguneratzea"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioak (<xliff:g id="PROCESS">%2$s</xliff:g> prozesua) berak aplikatutako StrictMode gidalerroa urratu du."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> prozesuak bere kabuz ezarritako StrictMode gidalerroak urratu ditu."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android bertsio-berritzen ari da…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Hasi saioa sarean"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Ezin da konektatu Internetera Wi-Fi bidez"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Ezin da konektatu Internetera Wi-Fi bidez"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Sakatu aukerak ikusteko"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> erabiltzen ari zara orain"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> Internetera konektatzeko gauza ez denean, <xliff:g id="NEW_NETWORK">%1$s</xliff:g> erabiltzen du gailuak. Agian kostuak ordaindu beharko dituzu."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> Internetera konektatzeko gauza ez denean, <xliff:g id="NEW_NETWORK">%1$s</xliff:g> erabiltzen du gailuak. Agian kostuak ordaindu beharko dituzu."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> erabiltzen ari zinen, baina <xliff:g id="NEW_NETWORK">%2$s</xliff:g> erabiltzen ari zara orain"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"datu mugikorrak"</item>
@@ -1130,7 +1133,8 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"sare mota ezezaguna"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ezin izan da Wi-Fi sarera konektatu"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" Interneteko konexio txarra du."</string>
+ <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+ <skip />
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Konektatzea baimendu nahi diozu?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s aplikazioak %2$s Wi-Fi sarera konektatu nahi du"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikazio bat"</string>
@@ -1626,7 +1630,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Laneko 2. <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Laneko 3. <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Pantailari aingura kentzeko, eduki sakatuta Atzera eta Ikuspegi orokorra botoiak"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Ezin zaio kendu aingura aplikazio honi"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Pantaila ainguratu da"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Aingura kendu zaio pantailari"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Eskatu PIN kodea aingura kendu aurretik"</string>
@@ -1635,7 +1638,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Administratzaileak instalatu du"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Administratzaileak eguneratu du"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Administratzaileak ezabatu du"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Bateriak gehiago iraun dezan, bateria-aurrezleak gailuaren errendimendua murrizten du, eta dardara, kokapen-zerbitzuak eta atzeko planoko datu gehienak mugatzen ditu. Posta elektronikoa, mezuak eta sinkronizatzen diren gainerako zerbitzuak ez dira eguneratuko ireki ezean.\n\nGailua kargatzeko konektatutakoan, bateria-aurrezlea automatikoki desaktibatuko da."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Bateriak gehiago iraun dezan, bateria-aurrezleak murriztu egiten du gailuaren errendimendua, eta mugatu egiten ditu dardara, kokapen-zerbitzuak eta atzeko planoko datu-erabilera gehienak. Ireki ezean, ez dira eguneratuko posta elektronikoa, mezuak eta sinkronizatzen diren gainerako zerbitzuak.\n\nGailua kargatzen hasten denean, automatikoki desaktibatzen da bateria-aurrezlea."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Datuen erabilera murrizteko, atzeko planoan datuak bidaltzea eta jasotzea galarazten die datu-aurrezleak aplikazio batzuei. Unean erabiltzen ari zaren aplikazioak atzi ditzake datuak, baina baliteke maiztasun txikiagoarekin atzitzea. Horrela, adibidez, baliteke irudiak ez erakustea haiek sakatu arte."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Datu-aurrezlea aktibatu?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Aktibatu"</string>
@@ -1782,14 +1785,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Larrialdi-mezuen proba"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Erantzun"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM txartela ezin da erabili ahotsa erabiltzeko"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM txartela ez dago hornituta ahotsa erabiltzeko"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM txartela ezin da erabili ahotsa erabiltzeko"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefonoa ezin da erabili ahotsa erabiltzeko"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Leiho gainerakorra"</string>
<string name="slice_more_content" msgid="8504342889413274608">"Beste <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Aplikazioaren bertsio berriena behar da lasterbideak funtziona dezan"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 54b4011..e1b4e0d 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"سرویس صوتی/اضطراری دردسترس نیست"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"موقتاً توسط شبکه داده دستگاه همراه در مکان شما ارائه نمیشود"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"شبکه دردسترس نیست"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"برای بهبود دریافت، نوع شبکه انتخابشده را در «تنظیمات > شبکه و اینترنت > شبکههای تلفن همراه > نوع شبکه ترجیحی» تغییر دهید."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"برای بهبود دریافت، نوع شبکه انتخابشده را در «تنظیمات > شبکه و اینترنت > شبکههای تلفن همراه > نوع شبکه ترجیحی» تغییر دهید."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"تماس ازطریق Wi-Fi فعال است"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"برای انجام تماسهای اضطراری به شبکه تلفن همراه نیاز دارید."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"هشدارها"</string>
@@ -212,6 +212,8 @@
<string name="global_action_power_off" msgid="4471879440839879722">"خاموش کردن"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"اضطراری"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"گزارش اشکال"</string>
+ <!-- no translation found for global_action_logout (935179188218826050) -->
+ <skip />
<string name="bugreport_title" msgid="2667494803742548533">"گرفتن گزارش اشکال"</string>
<string name="bugreport_message" msgid="398447048750350456">"این گزارش اطلاعات مربوط به وضعیت دستگاه کنونی شما را جمعآوری میکند تا به صورت یک پیام رایانامه ارسال شود. از زمان شروع گزارش اشکال تا آماده شدن برای ارسال اندکی زمان میبرد؛ لطفاً شکیبا باشید."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"گزارش تعاملی"</string>
@@ -977,7 +979,7 @@
<string name="addToDictionary" msgid="4352161534510057874">"افزودن به واژهنامه"</string>
<string name="deleteText" msgid="6979668428458199034">"حذف"</string>
<string name="inputMethod" msgid="1653630062304567879">"روش ورودی"</string>
- <string name="editTextMenuTitle" msgid="4909135564941815494">"عملکردهای متنی"</string>
+ <string name="editTextMenuTitle" msgid="4909135564941815494">"کنشهای متنی"</string>
<string name="email" msgid="4560673117055050403">"رایانامه"</string>
<string name="dial" msgid="1253998302767701559">"تماس"</string>
<string name="map" msgid="6521159124535543457">"مکانیابی"</string>
@@ -1051,6 +1053,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"در تنظیمات سیستم >برنامهها > مورد بارگیری شده آن را دوباره فعال کنید."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> از تنظیم فعلی اندازه نمایشگر پشتیبانی نمیکند و ممکن است رفتار غیرمنتظرهای داشته باشد."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"همیشه نشان داده شود"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> برای نسخه ناسازگار سیستمعامل Android ساخته شده است و ممکن است رفتاری برخلاف انتظار داشته باشد. ممکن است نسخه بهروزی از برنامه در دسترس باشد."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"همیشه نشان داده شود"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"بررسی وجود بهروزرسانی"</string>
<string name="smv_application" msgid="3307209192155442829">"برنامه <xliff:g id="APPLICATION">%1$s</xliff:g> (پردازش <xliff:g id="PROCESS">%2$s</xliff:g>) خطمشی StrictMode اجرایی خود را نقض کرده است."</string>
<string name="smv_process" msgid="5120397012047462446">"فرآیند <xliff:g id="PROCESS">%1$s</xliff:g> خطمشی StrictMode اجرای خودکار خود را نقض کرده است."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android در حال ارتقا است..."</string>
@@ -1116,10 +1121,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"ورود به سیستم شبکه"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi به اینترنت دسترسی ندارد"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi به اینترنت دسترسی ندارد"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"برای گزینهها ضربه بزنید"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"به <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> تغییر کرد"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"وقتی <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> دسترسی به اینترنت نداشته باشد، دستگاه از <xliff:g id="NEW_NETWORK">%1$s</xliff:g> استفاده میکند. ممکن است هزینههایی اعمال شود."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"وقتی <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> به اینترنت دسترسی نداشته باشد، دستگاه از <xliff:g id="NEW_NETWORK">%1$s</xliff:g> استفاده میکند. ممکن است هزینههایی اعمال شود."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"از <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> به <xliff:g id="NEW_NETWORK">%2$s</xliff:g> تغییر کرد"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"داده تلفن همراه"</item>
@@ -1130,7 +1135,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"نوع شبکه نامشخص"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"اتصال به Wi-Fi ممکن نیست"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" اتصال اینترنتی ضعیفی دارد."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" اتصال اینترنتی ضعیفی دارد."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"اتصال مجاز است؟"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"برنامه %1$s میخواهد به شبکه Wifi %2$s وصل شود"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"برنامه"</string>
@@ -1495,6 +1500,10 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"وقتی میانبر روشن است، اگر هر دو دکمه صدا را ۳ ثانیه فشار دهید یکی از قابلیتهای دسترسپذیری شروع میشود.\n\n قابلیت دسترسپذیری کنونی:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n میتوانید در «تنظیمات > دسترسپذیری»، قابلیت را تغییر دهید."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"خاموش کردن میانبر"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"استفاده از میانبر"</string>
+ <!-- no translation found for color_inversion_feature_name (4231186527799958644) -->
+ <skip />
+ <!-- no translation found for color_correction_feature_name (6779391426096954933) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"«میانبر دسترسپذیری» <xliff:g id="SERVICE_NAME">%1$s</xliff:g> را روشن کرد"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"«میانبر دسترسپذیری» <xliff:g id="SERVICE_NAME">%1$s</xliff:g> را خاموش کرد"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"قابلیتی را انتخاب کنید که هنگام ضربه زدن روی دکمه «دسترسپذیری» استفاده میشود:"</string>
@@ -1626,7 +1635,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"کار دوم <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"کار سوم <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"برای برداشتن پین این صفحه، دکمههای «برگشت» و «نمای کلی» را لمس کنید و نگهدارید"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"نمیتوان پین این برنامه را برداشت"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"صفحه پین شد"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"پین صفحه برداشته شد"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"درخواست کد پین قبل از برداشتن پین"</string>
@@ -1635,7 +1643,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"توسط سرپرست سیستم نصب شد"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"توسط سرپرست سیستم بهروزرسانی شد"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"توسط سرپرست سیستم حذف شد"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"برای کمک به بهبود عمر باتری، بهینهسازی باتری عملکرد دستگاهتان را کاهش میدهد و لرزش، سرویسهای مبتنی بر مکان، و دسترسی به اکثر دادهها در پسزمینه را محدود میکند. رایانامه، پیامرسانی و برنامههای دیگری که به همگامسازی وابستهاند، تا زمانیکه آنها را باز نکنید نمیتوانند بهروز شوند.\n\nبهینهسازی باتری بهصورت خودکار در هنگام شارژ شدن دستگاه خاموش میشود."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"برای کمک به بهبود عمر باتری، بهینهسازی باتری عملکرد دستگاهتان را کاهش میدهد و لرزش، خدمات مکان و دسترسی به اکثر دادهها در پسزمینه را محدود میکند. رایانامه، پیامرسانی و برنامههای دیگری که به همگامسازی وابسته هستند، تا زمانیکه آنها را باز نکنید نمیتوانند بهروز شوند.\n\nبهینهسازی باتری بهصورت خودکار در هنگام شارژ شدن دستگاه خاموش میشود."</string>
<string name="data_saver_description" msgid="6015391409098303235">"برای کمک به کاهش مصرف داده، «صرفهجویی داده» از ارسال و دریافت داده در پسزمینه از طرف بعضی برنامهها جلوگیری میکند. برنامهای که درحالحاضر استفاده میکنید میتواند به دادهها دسترسی داشته باشد اما دفعات دسترسی آن محدود است.این یعنی، برای مثال، تصاویر تا زمانی که روی آنها ضربه نزنید نشان داده نمیشوند."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"صرفهجویی داده روشن شود؟"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"روشن کردن"</string>
@@ -1682,6 +1690,8 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"شب آخر هفته"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"آخر هفته"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"رویداد"</string>
+ <!-- no translation found for zen_mode_default_every_night_name (3012363838882944175) -->
+ <skip />
<string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> آن را بیصدا کرد"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"دستگاهتان یک مشکل داخلی دارد، و ممکن است تا زمانی که بازنشانی دادههای کارخانه انجام نگیرد، بیثبات بماند."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"دستگاهتان یک مشکل داخلی دارد. برای جزئیات آن با سازندهتان تماس بگیرید."</string>
@@ -1782,14 +1792,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"آزمایش پیامهای اضطراری"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"پاسخ"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"سیمکارت برای عملیات صوتی مجاز نیست"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"سیمکارت مجوز لازم برای عملیات صوتی را ندارد"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"سیمکارت برای عملیات صوتی مجاز نیست"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"تلفن برای عملیات صوتی مجاز نیست"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"پنجره بازشو"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"این میانبر به جدیدترین نسخه برنامه نیاز دارد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 878f9eb..68b29df 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Ei ääni- tai hätäpuheluja"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Sijaintisi mobiiliverkko ei tarjoa tätä tilapäisesti."</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Ei yhteyttä verkkoon"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Voit yrittää parantaa kuuluvuutta vaihtamalla tyypin asetusta. Valitse Asetukset > Verkko > Internet > Mobiiliverkot > Ensisijainen verkko."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Voit yrittää parantaa kuuluvuutta vaihtamalla tyypin asetusta. Valitse Asetukset > Verkko > Internet > Mobiiliverkot > Ensisijainen verkko."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi-puhelut käytössä"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Hätäpuheluihin vaaditaan mobiiliverkko."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Ilmoitukset"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ota tämä uudelleen käyttöön kohdassa Järjestelmäasetukset > Sovellukset > Ladattu."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei tue nykyistä näytön kokoasetusta ja saattaa toimia odottamattomalla tavalla."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Näytä aina"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> on suunniteltu Android-käyttöjärjestelmän versiolle, joka ei ole yhteensopiva ja saattaa toimia odottamattomalla tavalla. Sovelluksesta voi olla saatavilla päivitetty versio."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Näytä aina"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Tarkista päivitykset"</string>
<string name="smv_application" msgid="3307209192155442829">"Sovellus <xliff:g id="APPLICATION">%1$s</xliff:g> (prosessi <xliff:g id="PROCESS">%2$s</xliff:g>) on rikkonut itse käyttöön ottamaansa StrictMode-käytäntöä."</string>
<string name="smv_process" msgid="5120397012047462446">"Prosessi <xliff:g id="PROCESS">%1$s</xliff:g> on rikkonut itse käyttöön ottamaansa StrictMode-käytäntöä."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Androidia päivitetään…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Kirjaudu verkkoon"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ei ole yhteydessä internetiin."</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi ei ole yhteydessä internetiin"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Näytä vaihtoehdot napauttamalla."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> otettiin käyttöön"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> otetaan käyttöön, kun <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ei voi muodostaa yhteyttä internetiin. Veloitukset ovat mahdollisia."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> otetaan käyttöön, kun <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ei voi muodostaa yhteyttä internetiin. Veloitukset ovat mahdollisia."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> poistettiin käytöstä ja <xliff:g id="NEW_NETWORK">%2$s</xliff:g> otettiin käyttöön."</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobiilidata"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tuntematon verkon tyyppi"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-yhteyden muodostaminen epäonnistui"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" : huono internetyhteys."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" : huono internetyhteys."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Sallitaanko yhteys?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Sovellus %1$s yrittää yhdistää Wi-Fi-verkkoon %2$s."</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Sovellus"</string>
@@ -1634,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Järjestelmänvalvoja asensi tämän."</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Järjestelmänvalvoja päivitti tämän."</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Järjestelmänvalvoja poisti tämän."</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Jos haluat parantaa akun kestoa, virransäästö vähentää laitteesi suorituskykyä ja rajoittaa värinää, sijaintipalveluita ja useimpia taustatietoja. Sähköposti, viestit ja muut synkronointiin perustuvat sovellukset eivät välttämättä päivity, ellet avaa niitä.\n\nVirransäästö poistuu käytöstä automaattisesti, kun laitteesi latautuu."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Parantaakseen akun kestoa virransäästö vähentää laitteesi suorituskykyä ja rajoittaa värinää, sijaintipalveluita ja useimpia taustatietoja. Sähköposti, viestit ja muut synkronointiin perustuvat sovellukset eivät välttämättä päivity, ellet avaa niitä.\n\nVirransäästö poistuu käytöstä automaattisesti, kun laitteesi latautuu."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Data Saver estää joitakin sovelluksia lähettämästä tai vastaanottamasta tietoja taustalla, jotta datan käyttöä voidaan vähentää. Käytössäsi oleva sovellus voi yhä käyttää dataa, mutta se saattaa tehdä niin tavallista harvemmin. Tämä voi tarkoittaa esimerkiksi sitä, että kuva ladataan vasta, kun kosketat sitä."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Otetaanko Data Saver käyttöön?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Ota käyttöön"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 658e951..a4c0a0f 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Aucun service vocal ou d\'urgence"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Ce service est temporairement non offert par le réseau cellulaire à l\'endroit où vous êtes"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Impossible de joindre le réseau"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Pour améliorer la réception, essayez de changer le type de réseau sélectionné, sous Paramètres > Réseaux et Internet > Réseaux cellulaires > Type de réseau préféré."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Pour améliorer la réception, essayez de changer le type de réseau sélectionné, sous Paramètres > Réseaux et Internet > Réseaux cellulaires > Type de réseau préféré."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Les appels Wi-Fi sont actifs"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Les appels d\'urgence nécessitent un réseau cellulaire."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Alertes"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Réactivez ce mode en accédant à Paramètres système > Applications > Téléchargements"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec le paramètre de taille d\'affichage actuel et peut se comporter de manière inattendue."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Toujours afficher"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> a été conçue pour une version incompatible du système d\'exploitation Android et peut se comporter de manière inattendue. Il se peut qu\'une version mise à jour de l\'application soit proposée."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Toujours afficher"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Vérifier la présence de mises à jour"</string>
<string name="smv_application" msgid="3307209192155442829">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) a enfreint ses propres règles du mode strict."</string>
<string name="smv_process" msgid="5120397012047462446">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> a enfreint ses propres règles du mode strict."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Mise à jour d\'Android…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Connectez-vous au réseau"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Le réseau Wi-Fi ne dispose d\'aucun accès à Internet"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Le réseau Wi-Fi ne dispose d\'aucun accès à Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Touchez pour afficher les options"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Passé au réseau <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quand <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas d\'accès à Internet. Des frais peuvent s\'appliquer."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quand <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas d\'accès à Internet. Des frais peuvent s\'appliquer."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Passé du réseau <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> au <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"données cellulaires"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un type de réseau inconnu"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossible de se connecter au Wi-Fi."</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" dispose d\'une mauvaise connexion Internet."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" dispose d\'une connexion Internet faible."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Autoriser la connexion?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"L\'application %1$s souhaite se connecter au réseau Wi-Fi %2$s."</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Une application"</string>
@@ -1634,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Installé par votre administrateur"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Mise à jour par votre administrateur"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Supprimé par votre administrateur"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Pour améliorer l\'autonomie de la pile, la fonction d\'économie d\'énergie réduit les performances de votre appareil et limite la vibration, les services de localisation ainsi que la plupart des données en arrière-plan. Les applications Courriel, Messages et d\'autres qui reposent sur la synchronisation ne peuvent pas se mettre à jour, sauf si vous les ouvrez. \n\nL\'économiseur d\'énergie se désactive automatiquement lorsque votre appareil est en charge."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Pour améliorer l\'autonomie de la pile, la fonction Économie d\'énergie réduit les performances de votre appareil et limite la vibration, les services de localisation ainsi que la plupart des données en arrière-plan. Les applications Courriel, Messages et d\'autres qui reposent sur la synchronisation ne peuvent pas se mettre à jour, sauf si vous les ouvrez. \n\nLa fonction Économie d\'énergie se désactive automatiquement lorsque votre appareil est en charge."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Pour aider à diminuer l\'utilisation des données, la fonction Économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Une application que vous utilisez actuellement peut accéder à des données, mais peut le faire moins souvent. Cela peut signifier, par exemple, que les images ne s\'affichent pas jusqu\'à ce que vous les touchiez."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Activer l\'Économiseur de données?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Activer"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 34e761b..c57684c 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Aucun service vocal/d\'urgence"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Momentanément non proposé par le réseau mobile à votre position"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Impossible d\'accéder au réseau"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Pour améliorer la réception, essayez de modifier le type sélectionné sous Paramètres > Réseau et Internet > Réseaux mobiles > Type de réseau préféré."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Pour améliorer la réception, essayez de modifier le type sélectionné sous Paramètres > Réseau et Internet > Réseaux mobiles > Type de réseau préféré."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Les appels Wi-Fi sont actifs"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Les appels d\'urgence requièrent un réseau mobile."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Alertes"</string>
@@ -262,7 +262,7 @@
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"accéder à vos contacts"</string>
<string name="permgrouprequest_contacts" msgid="1601591667800538208">"Permettre à <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> d\'accéder à vos contacts"</string>
- <string name="permgrouplab_location" msgid="7275582855722310164">"Position"</string>
+ <string name="permgrouplab_location" msgid="7275582855722310164">"Localisation"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"accéder à la position de l\'appareil"</string>
<string name="permgrouprequest_location" msgid="8903573681261610809">"Permettre à <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> d\'accéder à la position de cet appareil"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Agenda"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Réactivez ce mode en accédant à Paramètres système > Applications > Téléchargements"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec le paramètre de taille d\'affichage actuel et peut présenter un comportement inattendu."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Toujours afficher"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"L\'application <xliff:g id="APP_NAME">%1$s</xliff:g> a été conçue pour une version incompatible du système Android et peut présenter un comportement inattendu. Il est possible qu\'une version mise à jour de l\'application soit disponible."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Toujours afficher"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Rechercher les mises à jour"</string>
<string name="smv_application" msgid="3307209192155442829">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) a enfreint ses propres règles du mode strict."</string>
<string name="smv_process" msgid="5120397012047462446">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> a enfreint ses propres règles du mode strict."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Mise à jour d\'Android…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Se connecter au réseau"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Le réseau Wi-Fi ne dispose d\'aucun accès à Internet."</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Impossible de se connecter à Internet via le réseau Wi-Fi"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Appuyez ici pour afficher des options."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Nouveau réseau : <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> lorsque <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas de connexion Internet. Des frais supplémentaires peuvent s\'appliquer."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> lorsque <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas de connexion Internet. Des frais peuvent s\'appliquer."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Ancien réseau : <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>. Nouveau réseau : <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"données mobiles"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"type de réseau inconnu"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossible de se connecter au Wi-Fi."</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" dispose d\'une mauvaise connexion Internet."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" dispose d\'une mauvaise connexion Internet."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Autoriser la connexion ?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"L\'application %1$s souhaite se connecter au réseau Wi-Fi %2$s."</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Une application"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2e <xliff:g id="LABEL">%1$s</xliff:g> professionnelle"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3e <xliff:g id="LABEL">%1$s</xliff:g> professionnelle"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Pour annuler l\'épinglage de l\'écran, appuyez de manière prolongée sur les boutons Retour et Aperçu"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Impossible d\'annuler l\'épinglage de cette application"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Écran épinglé."</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Épinglage d\'écran annulé."</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Demander le code PIN avant d\'annuler l\'épinglage"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Installé par votre administrateur"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Mis à jour par votre administrateur"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Supprimé par votre administrateur"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Pour améliorer l\'autonomie de la batterie, l\'économiseur de batterie réduit les performances et désactive le vibreur, les services de localisation et la plupart des données en arrière-plan. Les messageries électroniques ou autres applications utilisant la synchronisation pourraient ne pas se mettre à jour, sauf si vous les ouvrez.\n\nL\'économiseur de batterie s\'éteint automatiquement lorsque l\'appareil est en charge."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Pour optimiser l\'autonomie de la batterie, l\'économiseur de batterie réduit les performances de votre appareil et limite le vibreur, les services de localisation et la plupart des données en arrière-plan. Vous devrez peut-être ouvrir manuellement vos applications d\'e-mail, de SMS/MMS et autres applications synchronisées pour les mettre à jour.\n\nL\'économiseur de batterie s\'éteint automatiquement lorsque l\'appareil est en charge."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Pour réduire la consommation de données, l\'économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Ainsi, les applications que vous utilisez peuvent toujours accéder aux données, mais pas en permanence. Par exemple, il se peut que les images ne s\'affichent pas tant que vous n\'appuyez pas dessus."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Activer l\'économiseur de données ?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Activer"</string>
@@ -1782,18 +1784,14 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test de messages d\'urgence"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Répondre"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"Carte SIM non autorisée pour les commandes vocales"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"Carte SIM non provisionnée pour les commandes vocales"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"Carte SIM non autorisée pour les commandes vocales"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Téléphone non autorisé pour les commandes vocales"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Fenêtre pop-up"</string>
<string name="slice_more_content" msgid="8504342889413274608">"<xliff:g id="NUMBER">%1$d</xliff:g> autres"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Ce raccourci nécessite la dernière version de l\'application"</string>
- <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Impossible de restaurer le raccourci, car l\'application n\'accepte pas la sauvegarde et la restauration"</string>
- <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Impossible de restaurer le raccourci en raison de la non-correspondance de la signature de l\'application"</string>
+ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Le raccourci ne peut pas être restauré car l\'application n\'accepte pas la sauvegarde et la restauration"</string>
+ <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Le raccourci ne peut pas être restauré car la signature de l\'application est différente"</string>
<string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Impossible de restaurer le raccourci"</string>
</resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index d0f100a..684b909 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Non hai servizo de chamadas de urxencia nin de voz"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"A rede de telefonía móbil non ofrece o servizo na túa localización temporalmente"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Non se pode conectar coa rede"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Para mellorar a recepción, proba a cambiar o tipo seleccionado en Configuración > Rede e Internet > Redes de telefonía móbil > Tipo de rede preferido."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Para mellorar a recepción, proba a cambiar o tipo seleccionado en Configuración > Rede e Internet > Redes de telefonía móbil > Tipo de rede preferido."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"As chamadas por wifi están activadas"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"As chamadas de urxencia precisan unha rede de telefonía móbil."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Alertas"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Volve activar esta función en Configuración do sistema > Aplicacións > Descargadas."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> non admite a configuración do tamaño de pantalla actual e quizais presente un comportamento inesperado."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Creouse a aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> para unha versión non compatible do sistema operativo Android e pode presentar un comportamento inesperado. É posible que estea dispoñible unha versión actualizada da aplicación."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Mostrar sempre"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Buscar actualización"</string>
<string name="smv_application" msgid="3307209192155442829">"A aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) infrinxiu a súa política StrictMode autoaplicada."</string>
<string name="smv_process" msgid="5120397012047462446">"O proceso <xliff:g id="PROCESS">%1$s</xliff:g> infrinxiu a política StrictMode de aplicación automática."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Estase actualizando Android…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Inicia sesión na rede"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"A wifi non ten acceso a Internet"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"A wifi non ten acceso a Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca para ver opcións."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Cambiouse a: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ten acceso a Internet. Pódense aplicar cargos."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ten acceso a Internet. Pódense aplicar cargos."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Cambiouse de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"datos móbiles"</item>
@@ -1130,7 +1133,8 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un tipo de rede descoñecido"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Non se puido conectar coa rede Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ten unha conexión a Internet deficiente."</string>
+ <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+ <skip />
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Queres permitir a conexión?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"A aplicación %1$s quere conectarse á rede wifi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Unha aplicación"</string>
@@ -1634,7 +1638,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Instalado polo teu administrador"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Actualizado polo teu administrador"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Eliminado polo teu administrador"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Para axudar a mellorar a duración da batería, a función de aforro da batería reduce o rendemento do teu dispositivo e limita a vibración, os servizos de localización e a maioría dos datos en segundo plano. É posible que o correo electrónico, as mensaxes e outras aplicacións que dependen da sincronización non se actualicen a menos que os abras. \n\nA función de aforro da batería desactívase automaticamente cando pos a cargar o teu dispositivo."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Para axudar a mellorar a duración da batería, a función Aforro de batería reduce o rendemento do dispositivo e limita a vibración, os servizos de localización e a maioría dos datos en segundo plano. É posible que o correo electrónico, as mensaxes e outras aplicacións que dependen da sincronización non se actualicen a menos que os abras. \n\nA función Aforro de batería desactívase automaticamente cando o dispositivo está cargando."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Para contribuír a reducir o uso de datos, o Economizador de datos impide que algunhas aplicacións envíen ou reciban datos en segundo plano. Cando esteas utilizando unha aplicación, esta poderá acceder aos datos, pero é posible que o faga con menos frecuencia. Por exemplo, é posible que as imaxes non se mostren ata que as toques."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Queres activar o economizador de datos?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Activar"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 1e9b38c..a6343ec 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"કોઈ વૉઇસ/કટોકટીની સેવા નથી"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"તમારા સ્થળે મોબાઇલ નેટવર્ક દ્વારા અસ્થાયીરૂપે ઑફર કરવામાં આવતી નથી"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"નેટવર્ક પર પહોંચી શકાતું નથી"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"રિસેપ્શનને બહેતર બનાવવા માટે, સેટિંગ્સ > નેટવર્ક અને ઇન્ટરનેટ > મોબાઇલ નેટવર્ક > પસંદગીના નેટવર્ક પ્રકાર પર પસંદ કરેલ પ્રકાર બદલવાનો પ્રયાસ કરો."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"રિસેપ્શનને બહેતર બનાવવા માટે, સેટિંગ > નેટવર્ક અને ઇન્ટરનેટ > મોબાઇલ નેટવર્ક > પસંદગીના નેટવર્ક પ્રકાર પર જઈને પસંદ કરેલ પ્રકાર બદલવાનો પ્રયાસ કરો."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"વાઇ-ફાઇ કૉલિંગ સક્રિય છે"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"કટોકટીના કૉલ માટે એક મોબાઇલ નેટવર્કની આવશ્યકતા છે."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"ચેતવણીઓ"</string>
@@ -1051,6 +1051,10 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"આને સિસ્ટમ સેટિંગ્સ > ઍપ્લિકેશનો > ડાઉનલોડ કરેલમાં ફરીથી સક્ષમ કરો."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> વર્તમાન પ્રદર્શન કદની સેટિંગનું સમર્થન કરતું નથી અને અનપેક્ષિત રીતે વર્તી શકે છે."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"હંમેશાં બતાવો"</string>
+ <!-- no translation found for unsupported_compile_sdk_message (4253168368781441759) -->
+ <skip />
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"હંમેશાં બતાવો"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"અપડેટ માટે તપાસો"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> ઍપ્લિકેશન (<xliff:g id="PROCESS">%2$s</xliff:g> પ્રક્રિયા)એ તેની સ્વ-લાગુ કરેલ StrictMode નીતિનું ઉલ્લંઘન કર્યું છે."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> પ્રક્રિયાએ તેની સ્વ-લાગુ કરેલ StrictMode નીતિનું ઉલ્લંઘન કર્યું છે."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android અપગ્રેડ થઈ રહ્યું છે..."</string>
@@ -1116,10 +1120,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"નેટવર્ક પર સાઇન ઇન કરો"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"વાઇ-ફાઇ ને કોઈ ઇન્ટરનેટ ઍક્સેસ નથી"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"વાઇ-ફાઇને કોઈ ઇન્ટરનેટ ઍક્સેસ નથી"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"વિકલ્પો માટે ટૅપ કરો"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> પર સ્વિચ કર્યું"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"જ્યારે <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> પાસે કોઈ ઇન્ટરનેટ ઍક્સેસ ન હોય ત્યારે ઉપકરણ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> નો ઉપયોગ કરે છે. શુલ્ક લાગુ થઈ શકે છે."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"જ્યારે <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> પાસે કોઈ ઇન્ટરનેટ ઍક્સેસ ન હોય ત્યારે ઉપકરણ <xliff:g id="NEW_NETWORK">%1$s</xliff:g>નો ઉપયોગ કરે છે. શુલ્ક લાગુ થઈ શકે છે."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> પરથી <xliff:g id="NEW_NETWORK">%2$s</xliff:g> પર સ્વિચ કર્યું"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"મોબાઇલ ડેટા"</item>
@@ -1130,7 +1134,8 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"અજાણ્યો નેટવર્ક પ્રકાર"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"વાઇ-ફાઇ સાથે કનેક્ટ કરી શકાયું નથી"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" નબળું ઇન્ટરનેટ કનેક્શન ધરાવે છે."</string>
+ <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+ <skip />
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"કનેક્શનની મંજૂરી આપીએ?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s ઍપ્લિકેશન Wifi નેટવર્ક %2$s થી કનેક્ટ થવા માગે છે"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"ઍપ્લિકેશન"</string>
@@ -1634,7 +1639,8 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"તમારા વ્યવસ્થાપક દ્વારા ઇન્સ્ટૉલ કરવામાં આવેલ છે"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"તમારા વ્યવસ્થાપક દ્વારા અપડેટ કરવામાં આવેલ છે"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"તમારા વ્યવસ્થાપક દ્વારા કાઢી નાખવામાં આવેલ છે"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"બૅટરી આવરદા વધુ સારી કરવામાં સહાય માટે, બૅટરી સેવર તમારા ઉપકરણના પ્રદર્શનને ઘટાડે છે અને વાઇબ્રેશન, સ્થાન સેવાઓ અને મોટાભાગના બૅકગ્રાઉન્ડ ડેટાને સીમિત કરે છે. ઇમેઇલ, મેસેજિંગ અને અન્ય ઍપ્લિકેશનો જે સમન્વયન પર આધાર રાખે છે તે તમે તેમને ખોલશો નહીં ત્યાં સુધી અપડેટ થઈ શકતી નથી.\n\nજ્યારે તમારું ઉપકરણ ચાર્જ થઈ રહ્યું હોય ત્યારે બૅટરી સેવર આપમેળે બંધ થઈ જાય છે."</string>
+ <!-- no translation found for battery_saver_description (5394663545060026162) -->
+ <skip />
<string name="data_saver_description" msgid="6015391409098303235">"ડેટા વપરાશને ઘટાડવામાં સહાય માટે, ડેટા સેવર કેટલીક ઍપ્લિકેશનોને પૃષ્ઠભૂમિમાં ડેટા મોકલવા અથવા પ્રાપ્ત કરવાથી અટકાવે છે. તમે હાલમાં ઉપયોગ કરી રહ્યાં છો તે ઍપ્લિકેશન ડેટાને ઍક્સેસ કરી શકે છે, પરંતુ તે આ ક્યારેક જ કરી શકે છે. આનો અર્થ એ હોઈ શકે છે, ઉદાહરણ તરીકે, છબીઓ ત્યાં સુધી પ્રદર્શિત થશે નહીં જ્યાં સુધી તમે તેને ટૅપ નહીં કરો."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ડેટા સેવર ચાલુ કરીએ?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ચાલુ કરો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 0a71c74..6f8fe0f 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -79,8 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"कोई वॉइस/आपातकालीन सेवा नहीं है"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"मोबाइल नेटवर्क आपके जगह पर इस समय यह सेवाएं नहीं दे पा रहा"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"नेटवर्क तक नहीं पहुंच पा रहे हैं"</string>
- <!-- no translation found for NetworkPreferenceSwitchSummary (7056776609127756440) -->
- <skip />
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"रिसेप्शन बेहतर करने के लिए, सेटिंग > नेटवर्क और इंटरनेट > मोबाइल नेटवर्क > पसंदीदा नेटवर्क प्रकार पर जाकर, चुना गया प्रकार बदलकर देखें."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"वाई-फ़ाई कॉलिंग सक्रिय है"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"आपातकालीन कॉल के लिए मोबाइल नेटवर्क ज़रूरी है."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"सूचनाएं"</string>
@@ -236,7 +235,7 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"नई सूचना"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"वर्चुअल कीबोर्ड"</string>
- <string name="notification_channel_physical_keyboard" msgid="7297661826966861459">"भौतिक कीबोर्ड"</string>
+ <string name="notification_channel_physical_keyboard" msgid="7297661826966861459">"सामान्य कीबोर्ड"</string>
<string name="notification_channel_security" msgid="7345516133431326347">"सुरक्षा"</string>
<string name="notification_channel_car_mode" msgid="3553380307619874564">"कार मोड"</string>
<string name="notification_channel_account" msgid="7577959168463122027">"खाते की स्थिति"</string>
@@ -469,15 +468,15 @@
<string name="permdesc_nfc" msgid="7120611819401789907">"ऐप्स को नियर फ़ील्ड कम्यूनिकेशन (NFC) टैग, कार्ड, और रीडर के साथ संचार करने देता है."</string>
<string name="permlab_disableKeyguard" msgid="3598496301486439258">"अपना स्क्रीन लॉक अक्षम करें"</string>
<string name="permdesc_disableKeyguard" msgid="6034203065077122992">"ऐप्स को कीलॉक और कोई भी संबद्ध पासवर्ड सुरक्षा अक्षम करने देता है. उदाहरण के लिए, इनकमिंग फ़ोन कॉल प्राप्त करते समय फ़ोन, कीलॉक को अक्षम कर देता है, फिर कॉल समाप्त होने पर कीलॉक को पुन: सक्षम कर देता है."</string>
- <string name="permlab_manageFingerprint" msgid="5640858826254575638">"अंगुली की छाप के लिए हार्डवेयर को प्रबंधित करें"</string>
- <string name="permdesc_manageFingerprint" msgid="178208705828055464">"अंगुली की छाप वाले टेम्पलेट का उपयोग करने के लिए जोड़ने और हटाने हेतु ऐप को विधियां प्रारंभ करने देती है."</string>
- <string name="permlab_useFingerprint" msgid="3150478619915124905">"अंगुली की छाप के लिए हार्डवेयर का उपयोग करें"</string>
- <string name="permdesc_useFingerprint" msgid="9165097460730684114">"ऐप के प्रमाणीकरण के लिए अंगुली की छाप हार्डवेयर का उपयोग करने देती है"</string>
+ <string name="permlab_manageFingerprint" msgid="5640858826254575638">"उंगली की छाप के लिए हार्डवेयर को प्रबंधित करें"</string>
+ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"उंगली की छाप वाले टेम्पलेट का उपयोग करने के लिए जोड़ने और हटाने हेतु ऐप को विधियां प्रारंभ करने देती है."</string>
+ <string name="permlab_useFingerprint" msgid="3150478619915124905">"उंगली की छाप के लिए हार्डवेयर का उपयोग करें"</string>
+ <string name="permdesc_useFingerprint" msgid="9165097460730684114">"ऐप के प्रमाणीकरण के लिए उंगली की छाप हार्डवेयर का उपयोग करने देती है"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"आंशिक फ़िंगरप्रिंट की पहचान की गई. कृपया पुनः प्रयास करें."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"फ़िंगरप्रिंट संसाधित नहीं हो सका. कृपया पुन: प्रयास करें."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"फ़िंगरप्रिंट सेंसर गंदा है. कृपया साफ़ करें और फिर कोशिश करें."</string>
- <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"अंगुली बहुत तेज़ी से चलाई गई है. कृपया पुनः प्रयास करें."</string>
- <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"अंगुली बहुत धीरे चलाई गई. कृपया पुनः प्रयास करें."</string>
+ <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"उंगली बहुत तेज़ी से चलाई गई है. कृपया फिर से कोशिश करें."</string>
+ <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"उंगली बहुत धीरे चलाई गई. कृपया फिर से कोशिश करें."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"फ़िंगरप्रिंट हार्डवेयर उपलब्ध नहीं है."</string>
@@ -487,7 +486,7 @@
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"बहुत अधिक प्रयास कर लिए गए हैं. बाद में पुन: प्रयास करें."</string>
<string name="fingerprint_error_lockout_permanent" msgid="5033251797919508137">"बहुत अधिक कोशिशें. फ़िंगरप्रिंट सेंसर अक्षम है."</string>
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"पुन: प्रयास करें."</string>
- <string name="fingerprint_name_template" msgid="5870957565512716938">"अंगुली <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <string name="fingerprint_name_template" msgid="5870957565512716938">"उंगली <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"फ़िंगरप्रिंट आइकॉन"</string>
@@ -1052,12 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"इसे सिस्टम सेटिंग > ऐप > डाउनलोड किए गए में फिर से चालू करें."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> वर्तमान स्क्रीन के आकार की सेटिंग का समर्थन नहीं करता है और अनपेक्षित रूप से व्यवहार कर सकता है."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"हमेशा दिखाएं"</string>
- <!-- no translation found for unsupported_compile_sdk_message (5030433583092006591) -->
- <skip />
- <!-- no translation found for unsupported_compile_sdk_show (2681877855260970231) -->
- <skip />
- <!-- no translation found for unsupported_compile_sdk_check_update (3312723623323216101) -->
- <skip />
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> को Android OS के जिस वर्शन के लिए बनाया गया था, यह उस पर काम नहीं करता है. शायद यह उम्मीद के मुताबिक काम न करे. हो सकता है कि ऐप्लिकेशन का नया वर्शन आ गया हो."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"हमेशा दिखाएं"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"देखें कि अपडेट उपलब्ध हैं या नहीं"</string>
<string name="smv_application" msgid="3307209192155442829">"ऐप्स <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ने उसकी स्वयं लागू होने वाली StrictMode नीति का उल्लंघन किया है."</string>
<string name="smv_process" msgid="5120397012047462446">"प्रक्रिया <xliff:g id="PROCESS">%1$s</xliff:g> ने उसकी स्व-प्रवर्तित StrictMode नीति का उल्लंघन किया है."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android अपग्रेड हो रहा है..."</string>
@@ -1123,12 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"नेटवर्क में साइन इन करें"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <!-- no translation found for wifi_no_internet (8938267198124654938) -->
- <skip />
+ <string name="wifi_no_internet" msgid="8938267198124654938">"वाई-फ़ाई के लिए इंटरनेट नहीं मिल रहा है"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"विकल्पों के लिए टैप करें"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> पर ले जाया गया"</string>
- <!-- no translation found for network_switch_metered_detail (775163331794506615) -->
- <skip />
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> में इंटरनेट की सुविधा नहीं होने पर डिवाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> का इस्तेमाल करता है. इसके लिए शुल्क लिया जा सकता है."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> से <xliff:g id="NEW_NETWORK">%2$s</xliff:g> पर ले जाया गया"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"मोबाइल डेटा"</item>
@@ -1212,9 +1206,9 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"शेयर करें"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"अस्वीकार करें"</string>
<string name="select_input_method" msgid="8547250819326693584">"कीबोर्ड बदलें"</string>
- <string name="show_ime" msgid="2506087537466597099">"भौतिक कीबोर्ड के सक्रिय होने के दौरान इसे स्क्रीन पर बनाए रखें"</string>
+ <string name="show_ime" msgid="2506087537466597099">"सामान्य कीबोर्ड के सक्रिय होने के दौरान इसे स्क्रीन पर बनाए रखें"</string>
<string name="hardware" msgid="194658061510127999">"वर्चुअल कीबोर्ड दिखाएं"</string>
- <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"भौतिक कीबोर्ड कॉन्फ़िगर करें"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"सामान्य कीबोर्ड कॉन्फ़िगर करें"</string>
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा और लेआउट चुनने के लिए टैप करें"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1643,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"आपके व्यवस्थापक ने इंस्टॉल किया है"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"आपके व्यवस्थापक ने अपडेट किया है"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"आपके व्यवस्थापक ने हटा दिया है"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"बैटरी लाइफ़ को बेहतर बनाने में मदद करने के लिए, बैटरी सेवर आपके डिवाइस के प्रदर्शन को कम कर देता है और कंपन (वाइब्रेशन), स्थान सेवाओं और ज़्यादातर बैकग्राउंड डेटा को सीमित कर देता है. हो सकता है कि ईमेल, मैसेज सेवा और सिंक पर आधारित अन्य ऐप तब तक ना खुलें जब तक कि आप उन्हें नहीं खोलते.\n\nजब आपका डिवाइस चार्ज हो रहा होता है तो बैटरी सेवर अपने आप बंद हो जाता है."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"बैटरी लाइफ़ को बेहतर बनाने में मदद करने के लिए, बैटरी सेवर आपके डिवाइस पर सिर्फ़ ज़रूरी ऐप्लिकेशन को काम करने देता है. यह कंपन (वाइब्रेशन), जगह की जानकारी से जुड़ी सेवाओं और ज़्यादातर बैकग्राउंड डेटा को सीमित कर देता है. हो सकता है कि ईमेल, मैसेज सेवा और सिंक पर आधारित दूसरे ऐप्लिकेशन तब तक ना खुलें जब तक कि आप उन्हें नहीं खोलते.\n\nजब आपका डिवाइस चार्ज हो रहा होता है, तब बैटरी सेवर अपने आप बंद हो जाता है."</string>
<string name="data_saver_description" msgid="6015391409098303235">"डेटा खर्च, कम करने के लिए डेटा सेवर कुछ ऐप को बैकग्राउंड में डेटा भेजने या पाने से रोकता है. आप फ़िलहाल जिस एेप का इस्तेमाल कर रहे हैं वह डेटा तक पहुंच सकता है, लेकिन ऐसा कभी-कभी ही हो पाएगा. उदाहरण के लिए, इसे समझिये कि तस्वीर तब तक दिखाई नहीं देंगी जब तक कि आप उन्हें टैप नहीं करते."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"डेटा बचाने की सेटिंग चालू करें?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"चालू करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 1b92d58..1be072e 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -80,7 +80,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Nema glasovnih i hitnih usluga"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Trenutačno nije u ponudi mobilne mreže na vašoj lokaciji"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Pristup mreži nije moguć"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Za bolji prijem pokušajte promijeniti vrstu odabranu u odjeljku Postavke > Mreža i internet > Mobilne mreže > Preferirana vrsta mreže."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Za bolji prijem pokušajte promijeniti vrstu odabranu u odjeljku Postavke > Mreža i internet > Mobilne mreže > Preferirana vrsta mreže."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Aktivni su Wi‑Fi pozivi"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Za hitne pozive potrebna je mobilna mreža."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Upozorenja"</string>
@@ -1071,6 +1071,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Omogućiti to ponovo u Postavkama sustava > Aplikacije > Preuzimanja."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava trenutačnu postavku veličine zaslona i može se ponašati neočekivano."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Uvijek prikaži"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> razvijena je za nekompatibilnu verziju OS-a Android i može se ponašati neočekivano. Možda je dostupna ažurirana verzija te aplikacije."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Uvijek prikaži"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Provjeri ažuriranja"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) prekršila je vlastito pravilo StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> prekršio je svoje vlastito pravilo StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android se nadograđuje…"</string>
@@ -1138,10 +1141,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Prijava na mrežu"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nema pristup internetu"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi nema pristup internetu"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Prelazak na drugu mrežu: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Kada <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, na uređaju se upotrebljava <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata naknade."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Kada <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, na uređaju se upotrebljava <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata naknade."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Mreža je promijenjena: <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> > <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobilni podaci"</item>
@@ -1152,7 +1155,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nepoznata vrsta mreže"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ne može se spojiti na Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internetsku vezu."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ima lošu internetsku vezu."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Dopustiti povezivanje?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacija %1$s traži povezivanje s Wi-Fi mrežom %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikacija"</string>
@@ -1651,7 +1654,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. <xliff:g id="LABEL">%1$s</xliff:g> za posao"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. <xliff:g id="LABEL">%1$s</xliff:g> za posao"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Da biste otkvačili ovaj zaslon, dodirnite i zadržite Natrag i Pregled"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Ova se aplikacija ne može otkvačiti"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Zaslon je pričvršćen"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Zaslon je otkvačen"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Traži PIN radi otkvačivanja"</string>
@@ -1660,7 +1662,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Instalirao administrator"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Ažurirao administrator"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Izbrisao administrator"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Da bi se produljilo trajanje baterije, ušteda baterije smanjuje performanse uređaja i ograničava vibraciju, usluge lokacije i većinu pozadinskih radnji. Aplikacije za e-poštu, slanje poruka i druge aplikacije koje se oslanjaju na sinkronizaciju možda se neće ažurirati ako ih ne otvorite.\n\nUšteda baterije isključuje se automatski dok se uređaj puni."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Da bi se produljilo trajanje baterije, Štednja baterije smanjuje rad uređaja i ograničava vibraciju, usluge lokacije i većinu pozadinskih podataka. Aplikacije za e-poštu, slanje poruka i druge aplikacije koje se oslanjaju na sinkronizaciju možda se neće ažurirati ako ih ne otvorite.\n\nŠtednja baterije isključuje se automatski dok se uređaj puni."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjio podatkovni promet, Štednja podatkovnog prometa onemogućuje nekim aplikacijama slanje ili primanje podataka u pozadini. Aplikacija koju trenutačno upotrebljavate može pristupiti podacima, no možda će to činiti rjeđe. To može značiti da se, na primjer, slike neće prikazivati dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Uključiti Uštedu podataka?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Uključi"</string>
@@ -1817,14 +1819,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test hitnih poruka"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Odgovori"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM nije dopušten za glasovne pozive"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM nije omogućen za glasovne pozive"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM nije dopušten za glasovne pozive"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefon nije dopušten za glasovne pozive"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Skočni prozor"</string>
<string name="slice_more_content" msgid="8504342889413274608">"još <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Za taj je prečac potrebna najnovija aplikacija"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index b1e5cb4..d9b4f61c 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Hang- és segélyszolgáltatás letiltva"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Az Ön tartózkodási helyén ideiglenesen nem áll rendelkezésre a mobilhálózaton"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"A hálózat nem érhető el"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"A vétel javítása érdekében próbálja módosítani a kiválasztott hálózattípust a Beállítások > Hálózat és internet > Mobilhálózatok > Preferált hálózattípus menüpontban."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"A vétel javítása érdekében próbálja módosítani a kiválasztott hálózattípust a Beállítások > Hálózat és internet > Mobilhálózatok > Preferált hálózattípus menüpontban."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"A Wi‑Fi-hívás aktív"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"A segélyhíváshoz mobilhálózatra van szükség."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Értesítések"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Újbóli engedélyezés itt: Rendszerbeállítások > Alkalmazások > Letöltve."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás nem támogatja a képernyőméret jelenlegi beállításait, ezért nem várt módon viselkedhet."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mindig megjelenik"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás az Android OS nem kompatibilis verziójához készült, ezért nem várt módon viselkedhet. Elképzelhető, hogy hozzáférhető az alkalmazás frissebb verziója."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Mindig látszik"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Frissítés keresése"</string>
<string name="smv_application" msgid="3307209192155442829">"A(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazás (<xliff:g id="PROCESS">%2$s</xliff:g> folyamat) megsértette az általa kényszerített Szigorú üzemmód irányelvet."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> folyamat megsértette az általa kényszerített Szigorú üzemmód irányelvet."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android frissítése folyamatban..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Bejelentkezés a hálózatba"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"A Wi-Fi-hálózaton nincs internetkapcsolat"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"A Wi-Fi-hálózaton nincs internetkapcsolat"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Koppintson a beállítások megjelenítéséhez"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Átváltva erre: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> használata, ha nincs internetkapcsolat <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>-kapcsolaton keresztül. A szolgáltató díjat számíthat fel."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> használata, ha nincs internet-hozzáférés <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>-kapcsolaton keresztül. A szolgáltató díjat számíthat fel."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Átváltva <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-hálózatról erre: <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobiladatok"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ismeretlen hálózati típus"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nem sikerült csatlakozni a Wi-Fi hálózathoz"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" rossz internetkapcsolattal rendelkezik."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" rossz internetkapcsolattal rendelkezik."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Engedélyezi a csatlakozást?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"A(z) %1$s alkalmazás szeretne csatlakozni a következő Wi-Fi hálózathoz: %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Egy alkalmazás"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. munkahelyi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. munkahelyi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"A képernyő rögzítésének feloldásához tartsa lenyomva a Vissza és az Áttekintés gombot"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Az alkalmazás rögzítését nem lehet feloldani"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Képernyő rögzítve"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Képernyő rögzítése feloldva"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"PIN-kód kérése a rögzítés feloldásához"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"A rendszergazda által telepítve"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"A rendszergazda által frissítve"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"A rendszergazda által törölve"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Az akkumulátoridő növelése érdekében az energiatakarékos mód csökkenti az eszköz teljesítményét, és korlátozza a rezgést, a helyszolgáltatásokat, valamint a legtöbb háttéradatot is. Előfordulhat, hogy azok az e-mail-, üzenetküldő és egyéb alkalmazások, amelyek szinkronizálására számít, csak akkor frissítenek, ha megnyitja azokat.\n\nAz energiatakarékos mód automatikusan kikapcsol, ha eszköze töltőn van."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Az akkumulátoridő növelése érdekében az Akkumulátorkímélő mód csökkenti az eszköz teljesítményét, és korlátozza a rezgést, a helyszolgáltatásokat, valamint a legtöbb háttéradatot is. Előfordulhat, hogy azok az e-mail-, üzenetküldő és egyéb alkalmazások, amelyek szinkronizálást használnak, csak akkor frissítenek, ha megnyitja őket.\n\nAz Akkumulátorkímélő mód automatikusan kikapcsol, ha eszköze töltőn van."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Az adatforgalom csökkentése érdekében az Adatforgalom-csökkentő megakadályozza, hogy egyes alkalmazások adatokat küldjenek vagy fogadjanak a háttérben. Az Ön által aktuálisan használt alkalmazások hozzáférhetnek az adatokhoz, de csak ritkábban. Ez például azt jelentheti, hogy a képek csak rákoppintás után jelennek meg."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Bekapcsolja az Adatforgalom-csökkentőt?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Bekapcsolás"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Vészhelyzetben küldött üzenetek tesztelése"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Válasz"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"A SIM-kártya nem engedélyezett a hanghoz"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"A SIM-kártya nem támogatott a hangnál"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"A SIM-kártya nem engedélyezett a hanghoz"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"A telefon nem engedélyezett a hanghoz"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Előugró ablak"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"A parancsikon működéséhez az alkalmazás legfrissebb verziójára van szükség"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 99ff527..094becd 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Ձայնային/արտակարգ իրավիճակների ծառայությունն անհասանելի է"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Ձեր գտնվելու վայրում ծառայությունը ժամանակավորապես չի տրամադրվում բջջային ցանցի կողմից"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Ցանցն անհասանելի է"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Ազդանշանի ընդունման որակը բարելավելու համար փոխեք ցանցի տեսակը՝ անցնելով Համակարգ > Ցանց և ինտերնետ > Բջջային ցանցեր > Ցանկալի ցանցի տեսակը։"</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Ազդանշանի ընդունման որակը լավացնելու համար փոխեք ցանցի տեսակը՝ անցնելով Կարգավորումներ > Ցանց և ինտերնետ > Բջջային ցանցեր > Ցանցի նախընտրած տեսակը։"</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi կանչերն ակտիվ են"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Շտապ կանչերի համար բջջային ցանց է անհրաժեշտ"</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Ծանուցումներ"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Կրկին ակտիվացնել սա Համակարգի կարգավորումներում &gt Ծրագրեր > Ներբեռնումներ:"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը չի աջակցում Էկրանի չափի ընթացիկ կարգավորումները, ինչի պատճառով կարող են խնդիրներ առաջանալ:"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Միշտ ցուցադրել"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ստեղծվել է Android OS-ի անհամատեղելի տարբերակի համար և կարող է սխալներով աշխատել: Ստուգեք՝ արդյոք հասանելի է հավելվածի թարմացված տարբերակը:"</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Միշտ ցույց տալ"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Ստուգել նոր տարբերակի առկայությունը"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> ծրագիրը (գործընթաց <xliff:g id="PROCESS">%2$s</xliff:g>) խախտել է իր ինքնահարկադրված Խիստ ռեժիմ քաղաքականությունը:"</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> գործընթացը խախտել է իր ինքնահարկադրված Խիստ ռեժիմ քաղաքականությունը:"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android-ը նորացվում է..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Մուտք գործեք ցանց"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ցանցը համացանցի միացում չունի"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi ցանցում ինտերնետ կապ չկա"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Հպեք՝ ընտրանքները տեսնելու համար"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Անցել է <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ցանցի"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Եթե <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ցանցն ինտերնետ կապ չունի, սարքն անցնում է <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ցանցի: Կարող են վճարներ գանձվել:"</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Երբ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ցանցում ինտերնետ կապ չի լինում, սարքն անցնում է <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ցանցի: Նման դեպքում կարող են վճարներ գանձվել:"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ցանցից անցել է <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ցանցի"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"բջջային ինտերնետ"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ցանցի անհայտ տեսակ"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Չհաջողվեց միանալ Wi-Fi-ին"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ունի թույլ ինտերնետ կապ:"</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ինտերնետային կապը թույլ է:"</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Թույլատրե՞լ կապը:"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s հավելվածը ցանկանում է միանալ %2$s Wifi ցանցին"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Հավելված"</string>
@@ -1634,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Տեղադրվել է ձեր ադմինիստրատորի կողմից"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Թարմացվել է ձեր ադմինիստրատորի կողմից"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Ջնջվել է ձեր ադմինիստրատորի կողմից"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Մարտկոցի աշխատանքի ժամկետը երկարացնելու համար տնտեսման ռեժիմում սահմանափակվում են սարքի արտադրողականությունը, թրթռոցը, տեղորոշման ծառայությունները և տվյալների ֆոնային փոխանցումը: Տվյալների համաժամեցումից կախված հավելվածները կարող են չթարմացվել, եթե դուք դրանք չգործարկեք:\n\n Մարտկոցի տնտեսումն ավտոմատ կերպով անջատվում է սարքի լիցքավորման ժամանակ։"</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Մարտկոցի աշխատանքի ժամկետը երկարացնելու համար տնտեսման ռեժիմում սահմանափակվում են սարքի արտադրողականությունը, թրթռոցը, տեղորոշման ծառայություններն ու տվյալների ֆոնային փոխանցումը: Տվյալների համաժամեցումից կախված՝ հավելվածները կարող են չթարմացվել, եթե դուք դրանք չգործարկեք:\n\nՄարտկոցի տնտեսումն ավտոմատ անջատվում է սարքի լիցքավորման ժամանակ:"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Թրաֆիկի տնտեսման ռեժիմում որոշ հավելվածների համար ֆոնային փոխանցումն անջատված է։ Հավելվածը, որն օգտագործում եք, կարող է տվյալներ փոխանցել և ստանալ, սակայն ոչ այնքան հաճախ: Օրինակ՝ պատկերները կցուցադրվեն միայն դրանց վրա սեղմելուց հետո։"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Միացնե՞լ թրաֆիկի խնայումը:"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Միացնել"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 2389d4d..c499ea7 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Tidak ada layanan panggilan suara/darurat"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Untuk sementara tidak ditawarkan oleh jaringan seluler di lokasi Anda"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Tidak dapat menjangkau jaringan"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Untuk menyempurnakan penerimaan sinyal, coba ubah jenis yang dipilih di Setelan > Jaringan & Internet > Jaringan seluler > Jenis jaringan pilihan."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Untuk menyempurnakan penerimaan sinyal, coba ubah jenis yang dipilih di Setelan > Jaringan & internet > Jaringan seluler > Jenis jaringan pilihan."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Panggilan Wi‑Fi aktif"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Panggilan darurat memerlukan jaringan seluler."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Notifikasi"</string>
@@ -212,6 +212,8 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Matikan perangkat"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Darurat"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Laporan bug"</string>
+ <!-- no translation found for global_action_logout (935179188218826050) -->
+ <skip />
<string name="bugreport_title" msgid="2667494803742548533">"Ambil laporan bug"</string>
<string name="bugreport_message" msgid="398447048750350456">"Ini akan mengumpulkan informasi status perangkat Anda saat ini, untuk dikirimkan sebagai pesan email. Harap bersabar, mungkin perlu waktu untuk memulai laporan bug hingga siap dikirim."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Laporan interaktif"</string>
@@ -495,7 +497,7 @@
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"nyalakan dan matikan sinkronisasi"</string>
<string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Memungkinkan aplikasi mengubah setelan sinkronisasi untuk sebuah akun. Misalnya, izin ini dapat digunakan untuk mengaktifkan sinkronisasi dari aplikasi Orang dengan sebuah akun."</string>
<string name="permlab_readSyncStats" msgid="7396577451360202448">"statistika baca sinkron"</string>
- <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Memungkinkan aplikasi membaca statistik sinkronisasi untuk sebuah akun, termasuk riwayat kejadian sinkronisasi dan berapa banyak data yang disinkronkan."</string>
+ <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Memungkinkan aplikasi membaca statistik sinkronisasi untuk sebuah akun, termasuk histori kejadian sinkronisasi dan berapa banyak data yang disinkronkan."</string>
<string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"baca konten simpanan USB Anda"</string>
<string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"baca konten kartu SD Anda"</string>
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Mengizinkan aplikasi membaca konten penyimpanan USB Anda."</string>
@@ -518,7 +520,7 @@
<string name="permdesc_bind_connection_service" msgid="4008754499822478114">"Memungkinkan aplikasi berinteraksi dengan layanan telepon untuk melakukan/menerima panggilan."</string>
<string name="permlab_control_incall_experience" msgid="9061024437607777619">"memberikan pengalaman pengguna dalam panggilan"</string>
<string name="permdesc_control_incall_experience" msgid="915159066039828124">"Memungkinkan aplikasi memberikan pengalaman pengguna dalam panggilan."</string>
- <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"baca riwayat penggunaan jaringan"</string>
+ <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"baca histori penggunaan jaringan"</string>
<string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Mengizinkan apl membaca penggunaan jaringan historis untuk apl dan jaringan tertentu."</string>
<string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"kelola kebijakan jaringan"</string>
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Mengizinkan apl mengelola kebijakan jaringan dan menentukan peraturan khusus apl."</string>
@@ -796,7 +798,7 @@
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
<string name="granularity_label_character" msgid="7336470535385009523">"karakter"</string>
<string name="granularity_label_word" msgid="7075570328374918660">"kata"</string>
- <string name="granularity_label_link" msgid="5815508880782488267">"tautan"</string>
+ <string name="granularity_label_link" msgid="5815508880782488267">"link"</string>
<string name="granularity_label_line" msgid="5764267235026120888">"baris"</string>
<string name="factorytest_failed" msgid="5410270329114212041">"Uji pabrik gagal"</string>
<string name="factorytest_not_system" msgid="4435201656767276723">"Tindakan FACTORY_TEST hanya didukung untuk paket yang terpasang pada /system/app."</string>
@@ -828,12 +830,12 @@
<string name="autofill_parish" msgid="8202206105468820057">"Kampung"</string>
<string name="autofill_area" msgid="3547409050889952423">"Area"</string>
<string name="autofill_emirate" msgid="2893880978835698818">"Emirat"</string>
- <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"baca riwayat dan bookmark web Anda"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Memungkinkan aplikasi membaca riwayat semua URL yang telah dikunjungi Browser, dan semua bookmark Browser. Catatan: izin ini tidak dapat diberlakukan oleh browser pihak ketiga atau aplikasi lain dengan kemampuan menjelajahi web."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"tulis riwayat dan bookmark web"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Memungkinkan aplikasi mengubah riwayat atau bookmark Browser yang tersimpan dalam tablet Anda. Izin ini memungkinkan aplikasi menghapus atau mengubah data Browser. Catatan: izin ini tidak dapat diberlakukan oleh browser pihak ketiga atau aplikasi lain dengan kemampuan menjelajahi web."</string>
- <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"Mengizinkan aplikasi untuk memodifikasi riwayat atau bookmark Browser yang disimpan di TV. Izin ini memungkinkan aplikasi untuk menghapus atau memodifikasi data Browser. Catatan: izin ini mungkin diterapkan oleh browser pihak ketiga atau aplikasi lain yang memiliki kemampuan menjelajah web."</string>
- <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Memungkinkan aplikasi mengubah riwayat atau bookmark Browser yang tersimpan dalam ponsel Anda. Izin ini memungkinkan aplikasi menghapus atau mengubah data Browser. Catatan: izin ini tidak dapat diberlakukan oleh browser pihak ketiga atau aplikasi lain dengan kemampuan menjelajahi web."</string>
+ <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"baca histori dan bookmark web Anda"</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Memungkinkan aplikasi membaca histori semua URL yang telah dikunjungi Browser, dan semua bookmark Browser. Catatan: izin ini tidak dapat diberlakukan oleh browser pihak ketiga atau aplikasi lain dengan kemampuan menjelajahi web."</string>
+ <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"tulis histori dan bookmark web"</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Memungkinkan aplikasi mengubah histori atau bookmark Browser yang tersimpan dalam tablet Anda. Izin ini memungkinkan aplikasi menghapus atau mengubah data Browser. Catatan: izin ini tidak dapat diberlakukan oleh browser pihak ketiga atau aplikasi lain dengan kemampuan menjelajahi web."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"Mengizinkan aplikasi untuk memodifikasi histori atau bookmark Browser yang disimpan di TV. Izin ini memungkinkan aplikasi untuk menghapus atau memodifikasi data Browser. Catatan: izin ini mungkin diterapkan oleh browser pihak ketiga atau aplikasi lain yang memiliki kemampuan menjelajah web."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Memungkinkan aplikasi mengubah histori atau bookmark Browser yang tersimpan dalam ponsel Anda. Izin ini memungkinkan aplikasi menghapus atau mengubah data Browser. Catatan: izin ini tidak dapat diberlakukan oleh browser pihak ketiga atau aplikasi lain dengan kemampuan menjelajahi web."</string>
<string name="permlab_setAlarm" msgid="1379294556362091814">"setel alarm"</string>
<string name="permdesc_setAlarm" msgid="316392039157473848">"Mengizinkan apl menyetel alarm di apl jam alarm yang terpasang. Beberapa apl jam alarm mungkin tidak menerapkan fitur ini."</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"tambahkan kotak pesan"</string>
@@ -1051,6 +1053,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktifkan kembali dialog ini di Setelan sistem > Apl > Terdownload."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak mendukung setelan Ukuran layar saat ini dan dapat menunjukkan perilaku yang tak diharapkan."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Selalu tampilkan"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> dibuat untuk versi OS Android yang tidak kompatibel dan mungkin berperilaku tak terduga. Versi aplikasi yang diupdate mungkin tersedia."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Selalu tampilkan"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Periksa apakah ada update"</string>
<string name="smv_application" msgid="3307209192155442829">"Apl <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) telah melanggar kebijakan StrictMode yang diberlakukannya sendiri."</string>
<string name="smv_process" msgid="5120397012047462446">"Proses <xliff:g id="PROCESS">%1$s</xliff:g> telah melanggar kebijakan StrictMode yang diberlakukan secara otomatis."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android sedang meningkatkan versi..."</string>
@@ -1116,10 +1121,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Masuk ke jaringan"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi tidak memiliki akses internet"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi tidak memiliki akses internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Ketuk untuk melihat opsi"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Dialihkan ke <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Perangkat menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> jika <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tidak memiliki akses internet. Tarif mungkin berlaku."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Perangkat menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> jika <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tidak memiliki akses internet. Tarif mungkin berlaku."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Dialihkan dari <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ke <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"data seluler"</item>
@@ -1130,7 +1135,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"jenis jaringan yang tidak dikenal"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Tidak dapat tersambung ke Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" memiliki sambungan internet yang buruk."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" memiliki sambungan internet yang buruk."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Izinkan hubungan?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikasi %1$s ingin tersambung ke Jaringan Wifi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikasi"</string>
@@ -1495,6 +1500,10 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Saat pintasan aktif, menekan kedua tombol volume selama 3 detik akan memulai fitur aksesibilitas.\n\n Fitur aksesibilitas saat ini:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Anda dapat mengubah fitur di Setelan > Aksesibilitas."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Nonaktifkan Pintasan"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Gunakan Pintasan"</string>
+ <!-- no translation found for color_inversion_feature_name (4231186527799958644) -->
+ <skip />
+ <!-- no translation found for color_correction_feature_name (6779391426096954933) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pintasan Aksesibilitas mengaktifkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pintasan Aksesibilitas menonaktifkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pilih fitur yang akan digunakan saat menge-tap tombol Aksesibilitas:"</string>
@@ -1634,7 +1643,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Diinstal oleh admin Anda"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Diupdate oleh admin Anda"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Dihapus oleh admin Anda"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Untuk membantu meningkatkan masa pakai baterai, penghemat baterai mengurangi kinerja perangkat dan membatasi getaran, layanan lokasi, dan sebagian besar data latar belakang. Email, pesan, dan aplikasi lain yang mengandalkan sinkronisasi mungkin tidak diperbarui kecuali jika dibuka.\n\nPenghemat baterai otomatis nonaktif jika perangkat diisi dayanya."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Untuk membantu meningkatkan masa pakai baterai, Penghemat Baterai mengurangi performa perangkat dan membatasi getaran, layanan lokasi, dan sebagian besar data latar belakang. Email, messaging, dan aplikasi lain yang mengandalkan sinkronisasi mungkin tidak diupdate kecuali jika dibuka.\n\nPenghemat Baterai otomatis nonaktif jika perangkat diisi dayanya."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Untuk membantu mengurangi penggunaan data, Penghemat Kuota Internet mencegah beberapa aplikasi mengirim atau menerima data di latar belakang. Aplikasi yang sedang digunakan dapat mengakses data, tetapi frekuensinya agak lebih jarang. Misalnya saja, gambar hanya akan ditampilkan setelah disentuh."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Aktifkan Penghemat Kuota Internet?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Aktifkan"</string>
@@ -1681,6 +1690,8 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Malam hari kerja"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Akhir pekan"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Acara"</string>
+ <!-- no translation found for zen_mode_default_every_night_name (3012363838882944175) -->
+ <skip />
<string name="muted_by" msgid="6147073845094180001">"Dinonaktifkan oleh <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Ada masalah dengan perangkat. Hal ini mungkin membuat perangkat jadi tidak stabil dan perlu dikembalikan ke setelan pabrik."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Ada masalah dengan perangkat. Hubungi produsen perangkat untuk informasi selengkapnya."</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 400228a..4fcf2d8 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Símtöl/neyðarsímtöl eru ekki í boði"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Ekki í boði á farsímakerfinu á þínum stað eins og er"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Ekki næst samband við símkerfi"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Reyndu að breyta valinni gerð í Stillingar > Netkerfi og internet > Farsímakerfi > Valin símkerfistegund til að bæta móttökuskilyrðin."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Reyndu að breyta valinni gerð í Stillingar > Netkerfi og internet > Farsímakerfi > Valin símkerfistegund til að bæta móttökuskilyrðin."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi-Fi símtöl eru virk"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Neyðarsímtöl krefjast farsímanets."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Tilkynningar"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Þú getur kveikt aftur á þessu undir Kerfisstillingar > Forrit > Sótt."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> styður ekki núverandi skjástærðarstillingu og gæti því ekki virkað sem skyldi."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Sýna alltaf"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> var hannað fyrir ósamhæfa útgáfu af Android stýrikerfinu og virkni þess kann að vera önnur en ætlast var til. Uppfærð útgáfa af forritinu kann að vera í boði."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Sýna alltaf"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Leita að uppfærslu"</string>
<string name="smv_application" msgid="3307209192155442829">"Forritið <xliff:g id="APPLICATION">%1$s</xliff:g> (ferli <xliff:g id="PROCESS">%2$s</xliff:g>) hefur brotið gegn eigin StrictMode-stefnu."</string>
<string name="smv_process" msgid="5120397012047462446">"Forritið <xliff:g id="PROCESS">%1$s</xliff:g> braut gegn eigin StrictMode-stefnu."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android er að uppfæra…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Skrá inn á net"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi netið er ekki með tengingu við internetið"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi er ekki með tengingu við internetið"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Ýttu til að sjá valkosti"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Skipt yfir á <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Tækið notar <xliff:g id="NEW_NETWORK">%1$s</xliff:g> þegar <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> er ekki með internetaðgang. Gjöld geta átt við."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Tækið notar <xliff:g id="NEW_NETWORK">%1$s</xliff:g> þegar <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> er ekki með internetaðgang. Gjöld kunna að eiga við."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Skipt úr <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> yfir í <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"farsímagögn"</item>
@@ -1130,7 +1133,8 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"óþekkt tegund netkerfis"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ekki var hægt að tengjast Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" er með lélegt netsamband."</string>
+ <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+ <skip />
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Leyfa tengingu?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Forritið %1$s vill tengjast Wi-Fi netinu %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Forrit"</string>
@@ -1626,7 +1630,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> í vinnu (2)"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> í vinnu (3)"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Til að losa þessa skjámynd skaltu halda hnöppunum „Til baka“ og „Yfirlit“ inni"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Ekki er hægt að losa þetta forrit"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Skjár festur"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Skjár opnaður"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Biðja um PIN-númer til að losa"</string>
@@ -1635,7 +1638,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Kerfisstjóri setti upp"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Kerfisstjóri uppfærði"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Kerfisstjóri eyddi"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Til að auka endingu rafhlöðunnar mun orkusparnaður draga úr afköstum tækisins og takmarka titring, staðsetningarþjónustu og megnið af bakgrunnsgögnum. Ekki er víst að tölvupóstur, skilaboð og önnur forrit sem reiða sig á samstillingu uppfærist nema þú opnir þau.\n\nSjálfkrafa er slökkt á orkusparnaði þegar tækið er í hleðslu."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Til að auka endingu rafhlöðunnar dregur rafhlöðusparnaður úr afköstum tækisins og takmarkar titring og flest bakgrunnsgögn. Ekki er víst að tölvupóstur, skilaboð og önnur forrit sem reiða sig á samstillingu verði uppfærð fyrr en þú opnar þau.\n\nSjálfkrafa er slökkt á rafhlöðusparnaði þegar tækið er í hleðslu."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Gagnasparnaður getur hjálpað til við að draga úr gagnanotkun með því að hindra forrit í að senda eða sækja gögn í bakgrunni. Forrit sem er í notkun getur náð í gögn, en gerir það kannski sjaldnar. Niðurstaðan gæti verið, svo dæmi sé tekið, að myndir séu ekki birtar fyrr en þú ýtir á þær."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Kveikja á gagnasparnaði?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Kveikja"</string>
@@ -1782,14 +1785,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Prófun neyðarskilaboða"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Svara"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM-kort er ekki heimilað fyrir rödd"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM-korti er ekki úthlutað fyrir rödd"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM-kort er ekki heimilað fyrir rödd"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Sími er ekki heimilaður fyrir rödd"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Sprettigluggi"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Nýjasta útgáfa forritsins þarf að vera til staðar til að þessi flýtileið virki"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 283d876..5f85317 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Nessun servizio di telefonia/emergenza"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Servizio temporaneamente non offerto dalla rete mobile nella tua località"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Impossibile raggiungere la rete"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Per migliorare la ricezione, prova a modificare il tipo selezionato in Impostazioni > Rete e Internet > Reti mobili > Tipo di rete preferito."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Per migliorare la ricezione, prova a modificare il tipo selezionato in Impostazioni > Rete e Internet > Reti mobili > Tipo di rete preferito."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Chiamate Wi‑Fi attive"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Per le chiamate di emergenza è necessaria una rete mobile."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Avvisi"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Riattivala in Impostazioni di sistema > Applicazioni > Scaricate."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> non supporta le dimensioni di visualizzazione attualmente impostate e potrebbe comportarsi in modo imprevisto."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostra sempre"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> è stata realizzata per una versione non compatibile del sistema operativo Android e potrebbe avere un comportamento imprevisto. Potrebbe essere disponibile una versione aggiornata dell\'app."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Mostra sempre"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Verifica la presenza di aggiornamenti"</string>
<string name="smv_application" msgid="3307209192155442829">"L\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) ha violato la norma StrictMode autoimposta."</string>
<string name="smv_process" msgid="5120397012047462446">"Il processo <xliff:g id="PROCESS">%1$s</xliff:g> ha violato la norma StrictMode autoimposta."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Aggiornamento di Android..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Accedi alla rete"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Connessione Wi-Fi priva di accesso Internet"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"La rete Wi-Fi non ha accesso a Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tocca per le opzioni"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Passato a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Il dispositivo utilizza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ha accesso a Internet. Potrebbero essere applicati costi."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Il dispositivo utilizza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ha accesso a Internet. Potrebbero essere applicati costi."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Passato da <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"dati mobili"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tipo di rete sconosciuto"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossibile connettersi alla rete Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ha una connessione Internet debole."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ha una connessione Internet debole."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Consentire la connessione?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"L\'applicazione %1$s vorrebbe connettersi alla rete Wi-Fi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Un\'applicazione"</string>
@@ -1625,17 +1628,16 @@
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> lavoro"</string>
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> di lavoro (2°)"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> di lavoro (3°)"</string>
- <string name="lock_to_app_toast" msgid="6820571533009838261">"Per rimuovere il blocco, tieni premuti i pulsanti Indietro e Panoramica"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Impossibile rimuovere il blocco per l\'app"</string>
- <string name="lock_to_app_start" msgid="6643342070839862795">"Schermata bloccata"</string>
- <string name="lock_to_app_exit" msgid="8598219838213787430">"Schermata sbloccata"</string>
+ <string name="lock_to_app_toast" msgid="6820571533009838261">"Per sganciare la schermata, tieni premuti i pulsanti Indietro e Panoramica"</string>
+ <string name="lock_to_app_start" msgid="6643342070839862795">"Schermata fissata"</string>
+ <string name="lock_to_app_exit" msgid="8598219838213787430">"Schermata sganciata"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Richiedi il PIN per lo sblocco"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Richiedi sequenza di sblocco prima di sbloccare"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Richiedi password prima di sbloccare"</string>
<string name="package_installed_device_owner" msgid="6875717669960212648">"Installato dall\'amministratore"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Aggiornato dall\'amministratore"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Eliminato dall\'amministratore"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Per aumentare la durata della batteria, la funzione di risparmio energetico riduce le prestazioni del dispositivo e limita vibrazione, servizi di geolocalizzazione e la maggior parte dei dati in background. App di email, messaggi e altre app che si basano sulla sincronizzazione potrebbero essere aggiornate soltanto all\'apertura.\n\nLa funzione di risparmio energetico viene disattivata automaticamente quando il dispositivo è in carica."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Per aumentare la durata della batteria, la funzione Risparmio energetico riduce le prestazioni del dispositivo e limita la vibrazione, i servizi di geolocalizzazione e la maggior parte dei dati in background. App di email, messaggi e altre app che si basano sulla sincronizzazione potrebbero essere aggiornate soltanto all\'apertura.\n\nLa funzione Risparmio energetico viene disattivata automaticamente quando il dispositivo è in carica."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Per contribuire a ridurre l\'utilizzo dei dati, la funzione Risparmio dati impedisce ad alcune app di inviare o ricevere dati in background. Un\'app in uso può accedere ai dati, ma potrebbe farlo con meno frequenza. Esempio: le immagini non vengono visualizzate finché non le tocchi."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Attivare Risparmio dati?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Attiva"</string>
@@ -1732,7 +1734,7 @@
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Connesso a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Tocca per visualizzare i file"</string>
<string name="pin_target" msgid="3052256031352291362">"Blocca"</string>
- <string name="unpin_target" msgid="3556545602439143442">"Sblocca"</string>
+ <string name="unpin_target" msgid="3556545602439143442">"Sgancia"</string>
<string name="app_info" msgid="6856026610594615344">"Informazioni app"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="5268556852031489931">"Avvio della demo…"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Testo messaggi di emergenza"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Rispondi"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM non consentita per la voce"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM non predisposta per la voce"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM non consentita per la voce"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefono non consentito per la voce"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Finestra popup"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Per questa scorciatoia è necessaria l\'app più recente"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 0f146ba..3ae2857 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -81,7 +81,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"אין אפשרות לבצע שיחות חירום ושיחות קוליות רגילות"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"הרשת הסלולרית במיקום הזה חסמה את השירות באופן זמני"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"לא ניתן להתחבר לרשת"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"כדי לשפר את הקליטה, כדאי לנסות לשנות את סוג הרשת ב\'הגדרות\' > \'רשת ואינטרנט\' > \'רשתות סלולריות\' > \'סוג רשת מועדף\'."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"כדי לשפר את הקליטה, כדאי לנסות לשנות את סוג הרשת בהגדרות > רשת ואינטרנט > רשתות סלולריות > סוג רשת מועדף."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"שיחות ה-Wi-Fi מופעלות"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"כדי לבצע שיחות חירום, יש להתחבר לרשת סלולרית."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"התראות"</string>
@@ -1091,6 +1091,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"אפשר תכונה זו מחדש ב\'הגדרות מערכת\' < Google Apps < \'הורדות\'."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> אינו תומך בהגדרת הגודל הנוכחית של התצוגה, והתנהגותו עשויה להיות בלתי צפויה."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"הצג תמיד"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> נבנתה לגרסה לא תואמת של מערכת ההפעלה של Android ועלולה להתנהג באופן לא צפוי. ייתכן שקיימת גרסה מעודכנת של האפליקציה."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"הצג תמיד"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"האם יש עדכון חדש?"</string>
<string name="smv_application" msgid="3307209192155442829">"האפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g> (תהליך <xliff:g id="PROCESS">%2$s</xliff:g>) הפר את מדיניות StrictMode באכיפה עצמית שלו."</string>
<string name="smv_process" msgid="5120397012047462446">"התהליך <xliff:g id="PROCESS">%1$s</xliff:g> הפר את מדיניות StrictMode באכיפה עצמית."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android מבצע שדרוג…"</string>
@@ -1160,10 +1163,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"היכנס לרשת"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"אין ל-Wi-Fi גישה לאינטרנט"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"לרשת ה-Wi-Fi אין גישה לאינטרנט"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"הקש לקבלת אפשרויות"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"מעבר אל <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"המכשיר משתמש ברשת <xliff:g id="NEW_NETWORK">%1$s</xliff:g> כשלרשת <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> אין גישה לאינטרנט. עשויים לחול חיובים."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"המכשיר משתמש ברשת <xliff:g id="NEW_NETWORK">%1$s</xliff:g> כשלרשת <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> אין גישה לאינטרנט. עשויים לחול חיובים."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"עבר מרשת <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> לרשת <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"חבילת גלישה"</item>
@@ -1174,7 +1177,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"סוג רשת לא מזוהה"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"אין אפשרות להתחבר ל-Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" אינו מחובר היטב לאינטרנט."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" בעל חיבור גרוע לאינטרנט."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"האם להתיר את החיבור?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"האפליקציה %1$s מנסה להתחבר אל רשת ה-Wi-Fi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"אפליקציה"</string>
@@ -1684,7 +1687,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"הותקנה על ידי מנהל המערכת"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"עודכנה על ידי מנהל המערכת"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"נמחקה על ידי מנהל המערכת"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"כדי לעזור בשיפור חיי הסוללה, תכונת החיסכון בסוללה מצמצמת את פעולות המכשיר ומגבילה רטט, שירותי מיקום ואת רוב נתוני הרקע. אימייל, העברת הודעות ואפליקציות אחרות המסתמכות על סנכרון עשויות שלא להתעדכן, אלא אם פותחים אותן.\n\nתכונת החיסכון בסוללה מושבתת אוטומטית כשהמכשיר בטעינה."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"כדי לעזור בשיפור חיי הסוללה, תכונת החיסכון בסוללה מצמצמת את פעולות המכשיר ומגבילה רטט, שירותי מיקום ואת רוב נתוני הרקע. אימייל, העברת הודעות ואפליקציות אחרות המסתמכות על סנכרון עשויות שלא להתעדכן, אלא אם תפתחו אותן.\n\nתכונת החיסכון בסוללה מושבתת אוטומטית כשהמכשיר בטעינה."</string>
<string name="data_saver_description" msgid="6015391409098303235">"כדי לסייע בהפחתת השימוש בנתונים, חוסך הנתונים (Data Saver) מונע מאפליקציות מסוימות שליחה או קבלה של נתונים ברקע. אפליקציה שבה אתה משתמש כרגע יכולה לגשת לנתונים, אבל בתדירות נמוכה יותר. משמעות הדבר היא, למשל, שתמונות יוצגו רק לאחר שתקיש עליהן."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"האם להפעיל את חוסך הנתונים (Data Saver)?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"הפעל"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index baff85c..11b4a0f 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"音声通話 / 緊急通報サービス停止"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"現在地のモバイル ネットワークでは一時的に提供されていません"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"ネットワークにアクセスできません"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"受信状態を改善するには、[設定] > [ネットワークとインターネット] > [モバイル ネットワーク] > [優先ネットワーク タイプ] で選択したタイプを変更してみてください。"</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"受信状態を改善するには、[設定] > [ネットワークとインターネット] > [モバイル ネットワーク] > [優先ネットワーク タイプ] で選択したタイプを変更してみてください。"</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi 通話が有効な状態です"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"緊急通報にはモバイル ネットワークが必要です。"</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"通知"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"[システム設定]>[アプリ]>[ダウンロード済み]で再度有効にします。"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」は現在の [表示サイズ] 設定に対応していないため、予期しない動作が発生するおそれがあります。"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"常に表示"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> は、互換性のない Android OS バージョン用にビルドされているため、予期しない動作が発生するおそれがあります。アプリの更新バージョンを利用できる場合があります。"</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"常に表示"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"アップデートをチェック"</string>
<string name="smv_application" msgid="3307209192155442829">"アプリ「<xliff:g id="APPLICATION">%1$s</xliff:g>」(プロセス「<xliff:g id="PROCESS">%2$s</xliff:g>」)でStrictModeポリシー違反がありました。"</string>
<string name="smv_process" msgid="5120397012047462446">"プロセス<xliff:g id="PROCESS">%1$s</xliff:g>でStrictModeポリシー違反がありました。"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Androidをアップグレードしています..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"ネットワークにログインしてください"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fiはインターネットに接続していません"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi‑Fi はインターネットに接続していません"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"タップしてその他のオプションを表示"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"「<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>」に切り替えました"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"端末で「<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>」によるインターネット接続ができない場合に「<xliff:g id="NEW_NETWORK">%1$s</xliff:g>」を使用します。通信料が発生することがあります。"</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"端末で「<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>」によるインターネット接続ができない場合に「<xliff:g id="NEW_NETWORK">%1$s</xliff:g>」を使用します。通信料が発生することがあります。"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"「<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>」から「<xliff:g id="NEW_NETWORK">%2$s</xliff:g>」に切り替えました"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"モバイルデータ"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"不明なネットワーク タイプ"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fiに接続できませんでした"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" はインターネット接続に問題があります。"</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" はインターネット接続に問題があります。"</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"接続を許可しますか?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"アプリ%1$sがWi-Fiネットワーク%2$sへの接続を希望しています"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"アプリ"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2 番目の仕事用<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3 番目の仕事用<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"この画面の固定を解除するには [戻る] ボタンと [最近] ボタンを押し続けます"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"このアプリの固定を解除できません"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"画面を固定しました"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"画面固定を解除しました"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"オフライン再生を解除する前にPINの入力を求める"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"管理者によりインストールされています"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"管理者により更新されています"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"管理者により削除されています"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"バッテリーを長持ちさせるため、バッテリーセーバーは端末のパフォーマンスを抑え、バイブレーション、位置情報サービス、大半のバックグラウンドデータを制限します。メール、SMSや、同期を使用するその他のアプリは、起動しても更新されないことがあります。\n\nバッテリーセーバーは端末の充電中は自動的にOFFになります。"</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"バッテリーを長持ちさせるため、バッテリー セーバーは端末のパフォーマンスを抑え、バイブレーション、位置情報サービス、大半のバックグラウンド データを制限します。同期を使用するメールやメッセージなどのアプリは起動しないと更新されない場合があります。\n\nバッテリー セーバーは端末の充電中は自動的に OFF になります。"</string>
<string name="data_saver_description" msgid="6015391409098303235">"データセーバーは、一部のアプリによるバックグラウンドでのデータ送受信を停止することでデータ使用量を抑制します。使用中のアプリからデータにアクセスすることはできますが、その頻度は低くなる場合があります。この影響として、たとえば画像はタップしないと表示されないようになります。"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"データセーバーを ON にしますか?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ON にする"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"テスト用緊急速報メール"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"返信"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"音声を使用できない SIM です"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"音声に対応していない SIM です"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"音声を使用できない SIM です"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"音声を使用できないスマートフォンです"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"ポップアップ ウィンドウ"</string>
<string name="slice_more_content" msgid="8504342889413274608">"他 <xliff:g id="NUMBER">%1$d</xliff:g> 件"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"このショートカットを使用するには、最新のアプリが必要です"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 85234cb..ce07805 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"ხმოვანი/გადაუდებელი ზარების სერვისი არ არის"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"დროებით არ არის შემოთავაზებული მობილური ქსელის მიერ თქვენს მდებარეობაზე"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"ქსელთან დაკავშირება ვერ ხერხდება"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"მიღების გასაუმჯობესებლად ცადეთ არჩეული ტიპის შეცვლა აქ: პარამეტრები > ქსელი და ინტერნეტი > მობილური ქსელები > ქსელის სასურველი ტიპი."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"მიღების გასაუმჯობესებლად ცადეთ არჩეული ტიპის შეცვლა აქ: პარამეტრები > ქსელი და ინტერნეტი > მობილური ქსელები > ქსელის სასურველი ტიპი."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"აქტიურია Wi‑Fi დარეკვა"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"გადაუდებელი ზარები საჭიროებს მობილურ ქსელს."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"გაფრთხილებები"</string>
@@ -212,6 +212,8 @@
<string name="global_action_power_off" msgid="4471879440839879722">"კვების გამორთვა"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"საგანგებო სამსახურები"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"ხარვეზის შესახებ ანგარიში"</string>
+ <!-- no translation found for global_action_logout (935179188218826050) -->
+ <skip />
<string name="bugreport_title" msgid="2667494803742548533">"შექმენით შეცდომის ანგარიში"</string>
<string name="bugreport_message" msgid="398447048750350456">"იგი შეაგროვებს ინფორმაციას თქვენი მოწყობილობის ამჟამინდელი მდგომარეობის შესახებ, რათა ის ელფოსტის შეტყობინების სახით გააგზავნოს. ხარვეზის ანგარიშის მომზადებასა და შეტყობინების გაგზავნას გარკვეული დრო სჭირდება. გთხოვთ, მოითმინოთ."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"ინტერაქტიული ანგარიში"</string>
@@ -1051,6 +1053,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ხელახალი გააქტიურება განყოფილებაში: სისტემის პარამეტრები > აპები > ჩამოტვირთულები."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის მიერ ეკრანის ამჟამინდელი პარამეტრები მხარდაუჭერელია და შეიძლება არასათანადოდ იმუშაოს."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ყოველთვის ჩვენება"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> შექმნილია Android-ის ოპერაციული სისტემის არათავსებადი ვერსიისთვის და შეიძლება გაუმართავად იმუშაოს. შესაძლოა ხელმისაწვდომი იყოს აპის განახლებული ვერსია."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"ყოველთვის ჩვენება"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"განახლების შემოწმება"</string>
<string name="smv_application" msgid="3307209192155442829">"აპმა <xliff:g id="APPLICATION">%1$s</xliff:g> (პროცესი <xliff:g id="PROCESS">%2$s</xliff:g>) დაარღვია საკუთარი StrictMode დებულება."</string>
<string name="smv_process" msgid="5120397012047462446">"ამ პროცესმა <xliff:g id="PROCESS">%1$s</xliff:g> დააზიანა საკუთარი StrictMode დებულება."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android ახალ ვერსიაზე გადადის…"</string>
@@ -1116,10 +1121,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"ქსელში შესვლა"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-ს არ აქვს ინტერნეტზე წვდომა"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi‑Fi ქსელს ინტერნეტზე წვდომა არ აქვს"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"შეეხეთ ვარიანტების სანახავად"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"ახლა გამოიყენება <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"თუ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ინტერნეტთან კავშირს დაკარგავს, მოწყობილობის მიერ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> იქნება გამოყენებული, რამაც შეიძლება დამატებითი ხარჯები გამოიწვიოს"</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"თუ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ინტერნეტთან კავშირს დაკარგავს, მოწყობილობის მიერ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> იქნება გამოყენებული, რამაც შეიძლება დამატებითი ხარჯები გამოიწვიოს."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"ახლა გამოიყენება <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> (გამოიყენებოდა <xliff:g id="NEW_NETWORK">%2$s</xliff:g>)"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"მობილური ინტერნეტი"</item>
@@ -1130,7 +1135,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"უცნობი ტიპის ქსელი"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-თან დაკავშირება ვერ მოხერხდა"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" აქვს ცუდი ინტერნეტ კავშირი."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ცუდი ინტერნეტ-კავშირი."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"გსურთ კავშირის დაშვება?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"განაცხადს %1$s სურს დაუკავშირდეს Wifi ქსელს %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"აპლიკაცია"</string>
@@ -1495,6 +1500,10 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"მალსახმობის ჩართვის შემთხვევაში, ხმის ორივე ღილაკზე 3 წამის განმავლობაში დაჭერით მარტივი წვდომის ფუნქცია ჩაირთვება.\n\n მარტივი წვდომის ამჟამინდელი ფუნქციაა:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ამ ფუნქციის შეცვლა შეგიძლიათ აქ: პარამეტრები > მარტივი წვდომა."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"მალსახმობის გამორთვა"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"მალსახმობის გამოყენება"</string>
+ <!-- no translation found for color_inversion_feature_name (4231186527799958644) -->
+ <skip />
+ <!-- no translation found for color_correction_feature_name (6779391426096954933) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"მარტივი წვდომის მალსახმობმა ჩართო <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"მარტივი წვდომის მალსახმობმა გამორთო <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"აირჩიეთ მარტივი წვდომის ღილაკზე შეხებისას გამოსაყენებელი ფუნქცია:"</string>
@@ -1626,7 +1635,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"მე-2 სამსახური <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"მე-3 სამსახური <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"ამ ეკრანის ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ ღილაკებს „უკან“ და „მიმოხილვა“"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"აპის ჩამაგრების მოხსნა ვერ მოხერხდება"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"ეკრანი დაფიქსირდა"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"ეკრანს ფიქსაცია მოეხსნა"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ფიქსაციის მოხსნამდე PIN-ის მოთხოვნა"</string>
@@ -1635,7 +1643,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"დაინსტალირებულია თქვენი ადმინისტრატორის მიერ"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"განახლებულია თქვენი ადმინისტრატორის მიერ"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"წაიშალა თქვენი ადმინისტრატორის მიერ"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"ბატარეის მოქმედების ვადის გაუმჯობესებისათვის, ბატარეის დამზოგი ამცირებს თქვენი მოწყობილობის ფუნქციონალობას და ზღუდავს ვიბრაციას, ადგილმდებარეობის სერვისებს და ძირითად ფონურ მონაცემებს. ელფოსტა, შეტყობინებები და სხვა სინქრონიზაციაზე დაყრდნობილი აპების განახლება არ მოხდება მათ გახსნამდე.\n\nბატარეის დამზოგველი ავტომატურად გამოირთვება, როდესაც თქვენს მოწყობილობას დამტენთან შეაერთებთ."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"ბატარეის მუშაობის ხანგრძლივობის გაუმჯობესებისათვის, ბატარეის დამზოგი ამცირებს თქვენი მოწყობილობის ფუნქციონალობას და ზღუდავს ვიბრაციას, მდებარეობის სერვისებს და ფონურ მონაცემთა უმეტესობას. ელფოსტა, შეტყობინებები და სხვა სინქრონიზაციაზე დამოკიდებული აპები მათ გახსნამდე არ განახლდება.\n\nბატარეის დამზოგი ავტომატურად გამოირთვება, როცა თქვენს მოწყობილობას დამტენთან შეაერთებთ."</string>
<string name="data_saver_description" msgid="6015391409098303235">"მობილური ინტერნეტის მოხმარების შემცირების მიზნით, მონაცემთა დამზოგველი ზოგიერთ აპს ფონურ რეჟიმში მონაცემთა გაგზავნასა და მიღებას შეუზღუდავს. თქვენ მიერ ამჟამად გამოყენებული აპი მაინც შეძლებს მობილურ ინტერნეტზე წვდომას, თუმცა ამას ნაკლები სიხშირით განახორციელებს. ეს ნიშნავს, რომ, მაგალითად, სურათები არ გამოჩნდება მანამ, სანამ მათ საგანგებოდ არ შეეხებით."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ჩაირთოს მონაცემთა დამზოგველი?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ჩართვა"</string>
@@ -1682,6 +1690,8 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"სამუშაო კვირის ღამე"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"შაბათ-კვირა"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"მოვლენა"</string>
+ <!-- no translation found for zen_mode_default_every_night_name (3012363838882944175) -->
+ <skip />
<string name="muted_by" msgid="6147073845094180001">"დადუმებულია <xliff:g id="THIRD_PARTY">%1$s</xliff:g>-ის მიერ"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"ფიქსირდება თქვენი მ ოწყობილობის შიდა პრობლემა და შეიძლება არასტაბილური იყოს, სანამ ქარხნულ მონაცემების არ განაახლებთ."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"ფიქსირდება თქვენი მოწყობილობის შიდა პრობლემა. დეტალებისათვის, მიმართეთ თქვენს მწარმოებელს."</string>
@@ -1782,14 +1792,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"სატესტო საგანგებო შეტყობინება"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"პასუხი"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM ბარათი ამ ხმისთვის დაუშვებელია"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM ბარათი ამ ხმისთვის უზრუნველყოფილი არაა"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM ბარათი ამ ხმისთვის დაუშვებელია"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"ტელეფონი ამ ხმისთვის დაუშვებელია"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"ამომხტარი ფანჯარა"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"ეს მალსახმობი საჭიროებს აპის უახლეს ვერსიას"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 5616972..0c5de0d 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Дауыстық/жедел қызметке қоңыраулар қызметі жоқ"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Орналасқан аймағыңызда мобильдік желі уақытша ұсынбады"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Желіге қосылу мүмкін емес"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Қабылдауды жақсарту үшін \"Параметрлер > Желі және интернет > Мобильді желілер және қалаулы желі түрі\" тармағынан түрді өзгертіп көріңіз."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Қабылдауды жақсарту үшін \"Параметрлер > Желі және интернет > Мобильді желілер > Қалаулы желі түрі\" тармағынан түрді өзгертіп көріңіз."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi қоңыраулары қосулы"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Жедел қызметке қоңырау шалу үшін мобильдік желі қажет."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Дабылдар"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Мұны «Жүйелік параметрлер» > «Қолданбалар» > «Жүктелгендер» тармағында қосыңыз."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасында \"Дисплей өлшемі\" параметрінің таңдалған мәніне қолдау көрсетілмейді, сондықтан дұрыс жұмыс істемеуі мүмкін."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Үнемі көрсету"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы сіздің Android OЖ-бен үйлеспейді және дұрыс жұмыс істемеуі ықтимал. Қолданбаның жаңартылған нұсқасы қолжетімді болуы мүмкін."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Үнемі көрсету"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Жаңартуды тексеру"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасы (<xliff:g id="PROCESS">%2$s</xliff:g> процесі) өзі қолданған StrictMode саясатын бұзды."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> үрдісі өздігінен күшіне енген ҚатаңРежим ережесін бұзды."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android жаңартылуда…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Желіге кіру"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi желісінде интернет байланысы жоқ"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi желісінде интернет байланысы жоқ"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Опциялар үшін түртіңіз"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> желісіне ауысты"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Құрылғы <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> желісінде интернетпен байланыс жоғалған жағдайда <xliff:g id="NEW_NETWORK">%1$s</xliff:g> желісін пайдаланады. Деректер ақысы алынуы мүмкін."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Құрылғы <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> желісінде интернетпен байланыс жоғалған жағдайда <xliff:g id="NEW_NETWORK">%1$s</xliff:g> желісін пайдаланады. Деректер ақысы алынуы мүмкін."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> желісінен <xliff:g id="NEW_NETWORK">%2$s</xliff:g> желісіне ауысты"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"мобильдік деректер"</item>
@@ -1130,7 +1133,8 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"желі түрі белгісіз"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi желісіне қосыла алмады"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" Интернет байланысы нашар."</string>
+ <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+ <skip />
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Қосылуға рұқсат ету керек пе?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s қолданбасы %2$s Wi-Fi желісіне қосылғысы келеді"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Қолданба"</string>
@@ -1626,7 +1630,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2-ші жұмыс профилі (<xliff:g id="LABEL">%1$s</xliff:g>)"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3-ші жұмыс профилі (<xliff:g id="LABEL">%1$s</xliff:g>)"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Бұл экранды босату үшін \"Артқа\" және \"Шолу\" түймелерін түртіп, ұстап тұрыңыз"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Бұл қолданбаны босату мүмкін емес"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Экран түйрелді"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Экран босатылды"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Босату алдында PIN кодын сұрау"</string>
@@ -1635,7 +1638,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Әкімші орнатқан"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Әкімші жаңартқан"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Әкімші жойған"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Батареяның қызмет көрсету мерзімін жақсарту үшін батарея үнемдегіш құрылғының өнімділігін төмендетеді және дірілді, орынды анықтау қызметтерін және фондық деректердің көпшілігін шектейді. Электрондық пошта, хабар алмасу және синхрондауға негізделген басқа қолданбалар ашқанша жаңартылмауы мүмкін.\n\nБатарея үнемдегіш құрылғы зарядталып жатқанда автоматты түрде өшеді."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Батареяның қызмет көрсету мерзімін жақсарту үшін Battery Saver функциясы құрылғының жұмыс өнімділігін төмендетеді, сондай-ақ дірілді, орынды анықтау қызметтерін және фондық деректердің көбін шектейді. Электрондық пошта, хабар алмасу және синхрондауға негізделген басқа қолданбалар ашқанша жаңартылмауы мүмкін.\n\nҚұрылғы зарядталып жатқанда, Battery Saver функциясы автоматты түрде өшеді."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Деректердің пайдаланылуын азайту үшін Трафикті үнемдеу функциясы кейбір қолданбаларға деректерді фондық режимде жіберуге немесе қабылдауға жол бермейді. Қазір қолданылып жатқан қолданба деректерді пайдалануы мүмкін, бірақ жиі емес. Мысалы, кескіндер оларды түрткенге дейін көрсетілмейді."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Data Saver функциясын қосу керек пе?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Қосу"</string>
@@ -1782,14 +1785,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Төтенше хабарлар сынағы"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Жауап"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM картасын дауысқа пайдалануға тыйым салынған"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM картасы дауысқа пайдалануға арналмаған"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM картасын дауысқа пайдалануға тыйым салынған"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Телефонды дауысқа пайдалануға тыйым салынған"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Қалқымалы терезе"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Бұл таңбаша ең соңғы қолданбаны қажет етеді"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index cfc79fe..edf3441 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"គ្មានសេវាកម្មសំឡេង/សង្រ្គោះបន្ទាន់ទេ"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"មិនបានផ្តល់ជូនដោយបណ្តាញចល័តនៅទីកន្លែងរបស់អ្នកជាបណ្តោះអាសន្ន"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"មិនអាចភ្ជាប់ទៅបណ្តាញបានទេ"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"ដើម្បីធ្វើឲ្យការទទួលរលកសញ្ញាប្រសើរជាងមុន សូមសាកល្បងប្តូរប្រភេទដែលបានជ្រើសរើសនៅ ការកំណត់ > បណ្តាញ និងអ៊ីនធឺណិត > បណ្តាញទូរសព្ទចល័ត > ប្រភេទបណ្តាញដែលចង់ប្រើ។"</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"ដើម្បីធ្វើឱ្យការទទួលរលកសញ្ញាប្រសើរជាងមុន សូមសាកល្បងប្តូរប្រភេទដែលបានជ្រើសរើសនៅការកំណត់ > បណ្តាញ និងអ៊ីនធឺណិត > បណ្តាញទូរសព្ទចល័ត > ប្រភេទបណ្តាញដែលចង់ប្រើ។"</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"ការហៅតាម Wi-Fi បានបើក"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"ការហៅបន្ទាន់តម្រូវឲ្យមានបណ្ដាញទូរសព្ទចល័ត។"</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"ការជូនដំណឹង"</string>
@@ -1053,6 +1053,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"បើកវាឡើងវិញក្នុងការកំណត់ប្រព័ន្ធ > កម្មវិធី > ទាញយក។"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនគាំទ្រការកំណត់ទំហំនៃការបង្ហាញបច្ចុប្បន្ន និងអាចមានសកម្មភាពខុសពីការរំពឹងទុក។"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"បង្ហាញជានិច្ច"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> ត្រូវបានបង្កើតឡើងសម្រាប់កំណែដែលមិនត្រូវគ្នាជាមួយប្រព័ន្ធប្រតិបត្តិការ Android ហើយអាចនឹងដំណើរការខុសប្រក្រតី។ អាចនឹងមានកំណែកម្មវិធីដែលបានដំឡើងជំនាន់។"</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"បង្ហាញជានិច្ច"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"រកមើលកំណែថ្មី"</string>
<string name="smv_application" msgid="3307209192155442829">"កម្មវិធី <xliff:g id="APPLICATION">%1$s</xliff:g> (ដំណើរការ <xliff:g id="PROCESS">%2$s</xliff:g>) បានបំពានគោលនយោបាយរបៀបតឹងរ៉ឹងអនុវត្តដោយខ្លួនឯង។"</string>
<string name="smv_process" msgid="5120397012047462446">"ដំណើរការ <xliff:g id="PROCESS">%1$s</xliff:g> បានបំពានគោលនយោបាយរបៀបតឹងរឹងបង្ខំដោយខ្លួនឯង"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android កំពុងធ្វើបច្ចុប្បន្នភាព..."</string>
@@ -1118,10 +1121,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"ចូលទៅបណ្តាញ"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi មិនមានអ៊ិនធឺណិតនោះទេ"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi មិនមានការតភ្ជាប់អ៊ីនធឺណិតទេ"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ប៉ះសម្រាប់ជម្រើស"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"បានប្តូរទៅ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"ឧបករណ៍ប្រើ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> នៅពេលដែល <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> គ្មានការតភ្ជាប់អ៊ីនធឺណិត។ អាចគិតប្រាក់លើការប្រើប្រាស់ទិន្នន័យ។"</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"ឧបករណ៍ប្រើ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> នៅពេលដែល <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> មិនមានការតភ្ជាប់អ៊ីនធឺណិត។ អាចគិតថ្លៃលើការប្រើប្រាស់ទិន្នន័យ។"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"បានប្តូរពី <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ទៅ <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"ទិន្នន័យទូរសព្ទចល័ត"</item>
@@ -1132,7 +1135,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ប្រភេទបណ្តាញមិនស្គាល់"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"មិនអាចតភ្ជាប់វ៉ាយហ្វាយ"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" មានការតភ្ជាប់អ៊ីនធឺណិតមិនល្អ។"</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" មានការតភ្ជាប់អ៊ីនធឺណិតមិនល្អ។"</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"អនុញ្ញាតភ្ជាប់?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"កម្មវិធី %1$s ចង់ភ្ជាប់ទៅបណ្តាញ Wifi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"កម្មវិធី"</string>
@@ -1628,7 +1631,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> ការងារទី 2"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> ការងារទី 3"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"ដើម្បីដកការខ្ទាស់អេក្រង់នេះ សូមចុចប៉ូតុងថយក្រោយ និងប៊ូតុងទិដ្ឋភាពឲ្យជាប់"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"មិនអាចដកការខ្ទាស់កម្មវិធីនេះបានទេ"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"បានភ្ជាប់អេក្រង់"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"មិនបានភ្ជាប់អេក្រង់"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"សួររកកូដ PIN មុនពេលផ្ដាច់"</string>
@@ -1637,7 +1639,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"ដំឡើងដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"ធ្វើបច្ចុប្បន្នភាពដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"លុបដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"ដើម្បីជួយឲ្យថាមពលថ្មប្រសើរឡើង កម្មវិធីសន្សំសំចៃថ្មកាត់បន្ថយប្រតិបត្តិការឧបករណ៍របស់អ្នក និងកម្រិតភាពញ័រ សេវាកម្មទីតាំង និងទិន្នន័យផ្ទៃខាងក្រោយស្ទើរតែទាំងអស់។ អ៊ីមែល ការផ្ញើសារ និងកម្មវិធីផ្សេងទៀតដែលពឹងផ្អែកលើការធ្វើសមកាលកម្មអាចនឹងមិនដំឡើងកំណែទេ លុះត្រាតែអ្នកបើកពួកវា។\n\nកម្មវិធីសន្សំសំចៃថ្មបិទដោយស្វ័យប្រវត្តិ នៅពេលដែលឧបករណ៍របស់អ្នកកំពុងសាកថ្ម។"</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"ដើម្បីជួយឱ្យកម្រិតថាមពលថ្មប្រសើរឡើង កម្មវិធីសន្សំថ្មកាត់បន្ថយប្រតិបត្តិការឧបករណ៍របស់អ្នក និងកម្រិតការញ័រ សេវាកម្មទីតាំង និងទិន្នន័យផ្ទៃខាងក្រោយភាគច្រើន។ អ៊ីមែល ការផ្ញើសារ និងកម្មវិធីផ្សេងទៀតដែលពឹងផ្អែកលើការធ្វើសមកាលកម្មមិនអាចដំឡើងជំនាន់បានទេ ប្រសិនបើអ្នកមិនបើកពួកវា។\n\nកម្មវិធីសន្សំថ្មបិទដោយស្វ័យប្រវត្តិ នៅពេលដែលឧបករណ៍របស់អ្នកកំពុងសាកថ្ម។"</string>
<string name="data_saver_description" msgid="6015391409098303235">"ដើម្បីជួយកាត់បន្ថយការប្រើប្រាស់ទិន្នន័យ កម្មវិធីសន្សំសំចៃទិន្នន័យរារាំងកម្មវិធីមួយចំនួនមិនឲ្យបញ្ជូន ឬទទួលទិន្នន័យនៅផ្ទៃខាងក្រោយទេ។ កម្មវិធីដែលអ្នកកំពុងប្រើនាពេលបច្ចុប្បន្នអាចចូលប្រើប្រាស់ទិន្នន័យបាន ប៉ុន្តែអាចនឹងមិនញឹកញាប់ដូចមុនទេ។ ឧទាហរណ៍ រូបភាពមិនបង្ហាញទេ លុះត្រាតែអ្នកប៉ះរូបភាពទាំងនោះ។"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"បើកកម្មវិធីសន្សំសំចៃទិន្នន័យឬ?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"បើក"</string>
@@ -1784,14 +1786,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"សារសាកល្បងពេលមានអាសន្ន"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"ឆ្លើយតប"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"ស៊ីមកាតមិនអនុញ្ញាតសម្រាប់ការហៅទូរសព្ទទេ"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"ស៊ីមកាតមិនមែនផ្តល់ជូនសម្រាប់ការហៅទូរសព្ទទេ"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"ស៊ីមកាតមិនអនុញ្ញាតសម្រាប់ការហៅទូរសព្ទទេ"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"ទូរសព្ទមិនអនុញ្ញាតសម្រាប់ការហៅទូរសព្ទទេ"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"វិនដូលេចឡើង"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"ផ្លូវកាត់នេះត្រូវការកម្មវិធីថ្មីបំផុត"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 609bef0..ede8ebb 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"ಧ್ವನಿ/ತುರ್ತು ಸೇವೆ ಇಲ್ಲ"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"ತಾತ್ಕಾಲಿಕವಾಗಿ ಮೊಬೈಲ್ ನೆಟ್ವರ್ಕ್ನಿಂದ ನಿಮ್ಮ ಸ್ಥಳದಲ್ಲಿ ಒದಗಿಸುತ್ತಿಲ್ಲ"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"ನೆಟ್ವರ್ಕ್ ತಲುಪಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"ನೆಟ್ವರ್ಕ್ ಸಂಪರ್ಕ ಪಡೆಯುವುದನ್ನು ಸುಧಾರಿಸಲು, ಆಯ್ಕೆ ಮಾಡಿರುವ ವಿಧವನ್ನು ಸೆಟ್ಟಿಂಗ್ಗಳು > ನೆಟ್ವರ್ಕ್ ಮತ್ತು ಇಂಟರ್ನೆಟ್ > ಮೊಬೈಲ್ ನೆಟ್ವರ್ಕ್ಗಳು > ಆದ್ಯತೆಯ ನೆಟ್ವರ್ಕ್ ವಿಧದಲ್ಲಿ ಬದಲಿಸಿ ನೋಡಿ."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"ನೆಟ್ವರ್ಕ್ ಸಂಪರ್ಕ ಪಡೆಯುವುದನ್ನು ಸುಧಾರಿಸಲು, ಆಯ್ಕೆ ಮಾಡಿರುವ ವಿಧವನ್ನು ಸೆಟ್ಟಿಂಗ್ಗಳು > ನೆಟ್ವರ್ಕ್ ಮತ್ತು ಇಂಟರ್ನೆಟ್ > ಮೊಬೈಲ್ ನೆಟ್ವರ್ಕ್ಗಳು > ಆದ್ಯತೆಯ ನೆಟ್ವರ್ಕ್ ವಿಧದಲ್ಲಿ ಬದಲಿಸಿ ನೋಡಿ."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"ವೈ‑ಫೈ ಕರೆಮಾಡುವಿಕೆ ಸಕ್ರಿಯವಾಗಿದೆ"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"ತುರ್ತು ಕರೆಗಳನ್ನು ಮಾಡಲು ಮೊಬೈಲ್ ನೆಟ್ವರ್ಕ್ ಅಗತ್ಯವಿದೆ."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"ಎಚ್ಚರಿಕೆಗಳು"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ಸಿಸ್ಟಂ ಸೆಟ್ಟಿಂಗ್ಗಳು > ಅಪ್ಲಿಕೇಶನ್ಗಳು > ಡೌನ್ಲೋಡ್ ಆಗಿರುವುದರಲ್ಲಿ ಇದನ್ನು ಮರು ಸಕ್ರಿಯಗೊಳಿಸಿ."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಪ್ರಸ್ತುತ ಪ್ರದರ್ಶನ ಗಾತ್ರದ ಸೆಟ್ಟಿಂಗ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ ಮತ್ತು ಅನಿರೀಕ್ಷಿತವಾಗಿ ವರ್ತಿಸಬಹುದು."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ಯಾವಾಗಲೂ ತೋರಿಸು"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Android OS ನ ಹೊಂದಾಣಿಕೆಯಾಗದ ಆವೃತ್ತಿ ಗಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನ್ನು ರಚಿಸಲಾಗಿದೆ ಮತ್ತು ಅನಿರೀಕ್ಷಿತವಾಗಿ ವರ್ತಿಸಬಹುದು. ಅಪ್ಲಿಕೇಶನ್ನ ಅಪ್ಡೇಟ್ ಮಾಡಲಾದ ಆವೃತ್ತಿ ಲಭ್ಯವಿರಬಹುದು."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"ಯಾವಾಗಲೂ ತೋರಿಸು"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"ಅಪ್ಡೇಟ್ಗಾಗಿ ಪರಿಶೀಲಿಸಿ"</string>
<string name="smv_application" msgid="3307209192155442829">"ಅಪ್ಲಿಕೇಶನ್ <xliff:g id="APPLICATION">%1$s</xliff:g> (ಪ್ರಕ್ರಿಯೆಯು <xliff:g id="PROCESS">%2$s</xliff:g>) ತನ್ನ ಸ್ವಯಂ-ಜಾರಿ ಕಠಿಣ ಮೋಡ್ ನೀತಿಯನ್ನು ಉಲ್ಲಂಘನೆ ಮಾಡಿದೆ."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> ಪ್ರಕ್ರಿಯೆಯು ತನ್ನ ಸ್ವಯಂ-ಜಾರಿ ಕಠಿಣ ಮೋಡ್ ನೀತಿಯನ್ನು ಉಲ್ಲಂಘನೆ ಮಾಡಿದೆ."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android ಅಪ್ಗ್ರೇಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"ನೆಟ್ವರ್ಕ್ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"ವೈ-ಫೈ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"ವೈ ಫೈ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ಆಯ್ಕೆಗಳಿಗೆ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶ ಹೊಂದಿಲ್ಲದಿರುವಾಗ, ಸಾಧನವು <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ಬಳಸುತ್ತದೆ. ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶ ಹೊಂದಿಲ್ಲದಿರುವಾಗ, ಸಾಧನವು <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ಬಳಸುತ್ತದೆ. ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ರಿಂದ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"ಮೊಬೈಲ್ ಡೇಟಾ"</item>
@@ -1130,7 +1133,8 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ಅಪರಿಚಿತ ನೆಟ್ವರ್ಕ್ ಪ್ರಕಾರ"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ವೈ-ಫೈ ಗೆ ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ಕಳಪೆ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿದೆ."</string>
+ <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+ <skip />
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"ಸಂಪರ್ಕವನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"%2$s ವೈಫೈ ನೆಟ್ವರ್ಕ್ಗೆ ಸಂಪರ್ಕಿಸಲು %1$s ಅಪ್ಲಿಕೇಶನ್ ಬಯಸುತ್ತದೆ"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"ಅಪ್ಲಿಕೇಶನ್"</string>
@@ -1634,7 +1638,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಸ್ಥಾಪಿಸಿದ್ದಾರೆ"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ಅಪ್ಡೇಟ್ ಮಾಡಲ್ಪಟ್ಟಿದೆ"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಅಳಿಸಿದ್ದಾರೆ"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"ಬ್ಯಾಟರಿಯ ಬಾಳಿಕೆಯನ್ನು ಸುಧಾರಿಸುವ ನಿಟ್ಟಿನಲ್ಲಿ, ಬ್ಯಾಟರಿ ಉಳಿಕೆಯು ನಿಮ್ಮ ಸಾಧನದ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ ಮತ್ತು ವೈಬ್ರೇಷನ್, ಸ್ಥಳ ಸೇವೆಗಳು ಹಾಗೂ ಹೆಚ್ಚಿನ ಹಿನ್ನೆಲೆ ಡೇಟಾವನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ. ಸಿಂಕ್ ಮಾಡುವಿಕೆಯನ್ನು ಅವಲಂಬಿಸಿರುವ ಇಮೇಲ್, ಸಂದೇಶ ಕಳುಹಿಸುವಿಕೆ ಮತ್ತು ಇತರ ಅಪ್ಲಿಕೇಶನ್ಗಳು ನೀವು ತೆರೆಯದ ಹೊರತು ಅಪ್ಡೇಟ್ ಆಗುವುದಿಲ್ಲ.\n\nನಿಮ್ಮ ಸಾಧನವು ಚಾರ್ಜ್ ಆಗುತ್ತಿರುವಾಗ ಬ್ಯಾಟರಿ ಉಳಿಕೆಯು ಆಫ್ ಆಗುತ್ತದೆ."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"ನಿಮ್ಮ ಬ್ಯಾಟರಿಯ ಬಾಳಿಕೆಯನ್ನು ಸುಧಾರಿಸಲು ಸಹಾಯ ಮಾಡಲು, ಬ್ಯಾಟರಿ ಉಳಿಕೆಯು ನಿಮ್ಮ ಸಾಧನದ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ ಮತ್ತು ವೈಬ್ರೇಷನ್, ಸ್ಥಳ ಸೇವೆಗಳು ಹಾಗೂ ಹೆಚ್ಚಿನ ಹಿನ್ನೆಲೆ ಡೇಟಾವನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ. ಸಿಂಕ್ ಮಾಡುವುದನ್ನು ಅವಲಂಬಿಸಿರುವ ಇಮೇಲ್, ಸಂದೇಶ ಕಳುಹಿಸುವಿಕೆ, ಮತ್ತು ಇತರ ಅಪ್ಲಿಕೇಶನ್ಗಳು ನೀವು ತೆರೆಯದ ಹೊರತು ನವೀಕರಣಗೊಳ್ಳುವುದಿಲ್ಲ.\n\nನಿಮ್ಮ ಸಾಧನವು ಚಾರ್ಜ್ ಆಗುತ್ತಿರುವ ಸಮಯದಲ್ಲಿ ಬ್ಯಾಟರಿ ಉಳಿಕೆಯು ಆಫ್ ಆಗುತ್ತದೆ."</string>
<string name="data_saver_description" msgid="6015391409098303235">"ಡೇಟಾ ಬಳಕೆ ಕಡಿಮೆ ಮಾಡುವ ನಿಟ್ಟಿನಲ್ಲಿ, ಡೇಟಾ ಸೇವರ್ ಕೆಲವು ಅಪ್ಲಿಕೇಶನ್ಗಳು ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಡೇಟಾ ಕಳುಹಿಸುವುದನ್ನು ಅಥವಾ ಸ್ವೀಕರಿಸುವುದನ್ನು ತಡೆಯುತ್ತದೆ. ನೀವು ಪ್ರಸ್ತುತ ಬಳಸುತ್ತಿರುವ ಅಪ್ಲಿಕೇಶನ್ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಬಹುದು ಆದರೆ ಪದೇ ಪದೇ ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಇದರರ್ಥ, ಉದಾಹರಣೆಗೆ, ನೀವು ಅವುಗಳನ್ನು ಟ್ಯಾಪ್ ಮಾಡುವವರೆಗೆ ಆ ಚಿತ್ರಗಳು ಕಾಣಿಸಿಕೊಳ್ಳುವುದಿಲ್ಲ."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ಡೇಟಾ ಉಳಿಸುವಿಕೆಯನ್ನು ಆನ್ ಮಾಡುವುದೇ?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ಆನ್ ಮಾಡಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 1976bbe..679ca75 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"음성/긴급 서비스를 이용할 수 없음"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"현재 위치에서 모바일 네트워크가 서비스 제공을 일시적으로 중단했습니다."</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"네트워크에 연결할 수 없습니다."</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"수신 상태를 개선하려면 설정 > 네트워크 및 인터넷 > 모바일 네트워크 > 기본 네트워크 유형에서 선택된 유형을 변경해 보세요."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"수신 상태를 개선하려면 설정 > 네트워크 및 인터넷 > 모바일 네트워크 > 기본 네트워크 유형에서 선택된 유형을 변경해 보세요."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi 통화가 활성화됨"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"긴급 전화를 걸려면 모바일 네트워크에 연결되어 있어야 합니다."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"알림"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"시스템 설정 > 앱 > 다운로드로 이동하여 이 모드를 다시 사용하도록 설정합니다."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱은 현재 디스플레이 크기 설정을 지원하지 않으며 예기치 않게 동작할 수 있습니다."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"항상 표시"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g>은(는) 호환되지 않는 Android OS 버전에 최적화되어 있으며, 정상적으로 작동하지 않을 수 있습니다. 업데이트된 버전의 앱을 사용할 수도 있습니다."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"항상 표시"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"업데이트 확인"</string>
<string name="smv_application" msgid="3307209192155442829">"앱 <xliff:g id="APPLICATION">%1$s</xliff:g>(프로세스 <xliff:g id="PROCESS">%2$s</xliff:g>)이(가) 자체 시행 StrictMode 정책을 위반했습니다."</string>
<string name="smv_process" msgid="5120397012047462446">"프로세스(<xliff:g id="PROCESS">%1$s</xliff:g>)가 자체 시행 StrictMode 정책을 위반했습니다."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android 업그레이드 중.."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"네트워크에 로그인"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi가 인터넷에 연결되어 있지 않습니다."</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi가 인터넷에 연결되어 있지 않습니다"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"탭하여 옵션 보기"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>(으)로 전환"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>이(가) 인터넷에 연결되지 않는 경우 기기에서 <xliff:g id="NEW_NETWORK">%1$s</xliff:g>을(를) 사용합니다. 요금이 부과될 수 있습니다."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>(으)로 인터넷에 연결할 수 없는 경우 기기에서 <xliff:g id="NEW_NETWORK">%1$s</xliff:g>이(가) 사용됩니다. 요금이 부과될 수 있습니다."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>에서 <xliff:g id="NEW_NETWORK">%2$s</xliff:g>(으)로 전환"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"모바일 데이터"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"알 수 없는 네트워크 유형"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi에 연결할 수 없습니다"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 인터넷 연결 상태가 좋지 않습니다."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" 인터넷 연결 상태가 좋지 않습니다."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"연결을 허용하시겠습니까?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s 애플리케이션에서 %2$s Wi-Fi 네트워크에 연결하려고 합니다."</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"앱"</string>
@@ -1634,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"관리자에 의해 설치되었습니다."</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"관리자에 의해 업데이트되었습니다."</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"관리자에 의해 삭제되었습니다."</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"배터리 수명 개선을 위해, 배터리 세이버는 기기의 성능을 줄이고 진동, 위치 서비스 및 대부분의 백그라운드 데이터를 제한합니다. 이메일, 메시지 및 동기화에 의존하는 기타 앱은 앱을 열 때까지 업데이트되지 않을 수 있습니다.\n\n배터리 세이버는 기기를 충전 중일 때는 자동으로 사용 중지됩니다."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"배터리 세이버는 배터리 수명 개선을 위해 기기 성능을 줄이고 진동, 위치 서비스 및 대부분의 백그라운드 데이터를 제한합니다. 이메일, 메시지 및 동기화에 의존하는 기타 앱은 앱을 열 때까지 업데이트되지 않을 수 있습니다.\n\n배터리 세이버는 기기가 충전 중일 때는 자동으로 사용 중지됩니다."</string>
<string name="data_saver_description" msgid="6015391409098303235">"데이터 사용량을 줄이기 위해 데이터 절약 모드는 일부 앱이 백그라운드에서 데이터를 전송하거나 수신하지 못하도록 합니다. 현재 사용 중인 앱에서 데이터에 액세스할 수 있지만 빈도가 줄어듭니다. 예를 들면, 이미지를 탭하기 전에는 이미지가 표시되지 않습니다."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"데이터 절약 모드를 사용할까요?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"사용 설정"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index a1cc479..daa824c 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Бардык чалуулар жана кызматтар бөгөттөлгөн"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Өзгөчө кырдаалдагы кызматтар сиз жайгашкан жердеги мобилдик тармак тарабынан убактылуу бөгөттөлгөн"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Тармакка туташпай жатат"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Кабыл алуу мүмкүнчүлүгүн жакшыртуу үчүн Жөндөөлөр > Тармак жана Интернет > Мобилдик тармактар > Тандалган тармак бөлүмүнөн тармактын түрүн өзгөртүп көрүңүз."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Кабыл алуу мүмкүнчүлүгүн жакшыртуу үчүн Жөндөөлөр > Тармак жана Интернет > Мобилдик тармактар > Тандалган тармак бөлүмүнөн тармактын түрүн өзгөртүп көрүңүз."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi аркылуу чалуу жүрүп жатат"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Шашылыш чалуу үчүн мобилдик тармак талап кылынат."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Эскертүүлөр"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Муну тутум жөндөөлөрүнөн кайра иштетүү > Колдонмолор > Жүктөлүп алынган."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу көрүнүштүн тандалган өлчөмүн экранда көрсөтө албайт жана туура эмес иштеши мүмкүн."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Ар дайым көрсөтүлсүн"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> Android OS тутуму менен иштеген түзмөктүн шайкеш келбеген версиясы үчүн орнотулган колдонмо жана туура эмес иштеши мүмкүн. Колдонмонун жаңыртылган версиясы жеткиликтүү болушу мүмкүн."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Ар дайым көрсөтүлсүн"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Жаңыртууну издөө"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосу (<xliff:g id="PROCESS">%2$s</xliff:g> процесси) өз алдынча иштеткен StrictMode саясатын бузду."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> процесси өзүнүн мажбурланган StrictMode саясатын бузуп койду."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android жаңыртылууда…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Тармакка кирүү"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi тармагы Интернетке туташпай турат"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi тармагы Интернетке туташпай турат"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Параметрлерди ачуу үчүн таптап коюңуз"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> тармагына которуштурулду"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> тармагы Интернетке туташпай турганда, түзмөгүңүз <xliff:g id="NEW_NETWORK">%1$s</xliff:g> тармагын колдонот. Акы алынышы мүмкүн."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> тармагы Интернетке туташпай турганда, түзмөгүңүз <xliff:g id="NEW_NETWORK">%1$s</xliff:g> тармагын колдонот. Акы алынышы мүмкүн."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> дегенден <xliff:g id="NEW_NETWORK">%2$s</xliff:g> тармагына которуштурулду"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"мобилдик трафик"</item>
@@ -1130,7 +1133,8 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"белгисиз тармак түрү"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi менен туташуу түзүлбөдү"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" хотспотунун интернет байланышы начар."</string>
+ <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+ <skip />
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Туташууга уруксатпы?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s колдонмосу %2$s Wifi тармагына туташкысы келет"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Колдонмо"</string>
@@ -1627,7 +1631,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2-жумуш <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3-жумуш <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Бул экранды бошотуу үчүн \"Артка\" жана \"Сереп салуу\" баскычтарын басып, кармап туруңуз"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Бул колдонмону бошотууга болбойт"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Экран кадалды"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Экран бошотулду"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Бошотуудан мурун PIN суралсын"</string>
@@ -1636,7 +1639,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Администраторуңуз орнотуп койгон"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Администраторуңуз жаңыртып койгон"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Администраторуңуз жок кылып салган"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Батареянын өмүрүн узартуу үчүн, кубатты үнөмдөө режими түзмөгүңүздүн ишин солгундатып, дирилдөө функциясын, жайгашкан жерди аныктоо кызматын жана дайындардын фондо өткөрүлүшүн чектеп коёт. Электрондук почта, билдирүү жазышуу сыяктуу шайкештириле турган дайындар колдонмо ачылганда гана жаңырат.\n\nБатареянын кубатын үнөмдөө режими түзмөгүңүз кубатталып жатканда автоматтык түрдө өчүп калат."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Батареянын өмүрүн узартуу үчүн Батареяны үнөмдөгүч режиминде түзмөгүңүздүн ишинин майнаптуулугу азайып, дирилдөө, жайгашкан жерди аныктоо кызматтары жана фондук дайындардын көпчүлүгү чектелип калат. Электрондук почта, жазышуу жана башка шайкештирилүүчү колдонмолор ачылмайынча, жаңыртылбай калышы мүмкүн.\n\nБатареяны үнөмдөгүч режими түзмөгүңүз кубатталып жатканда автоматтык түрдө өчүп калат."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Трафикти үнөмдөө режиминде айрым колдонмолор дайындарды фондо өткөрө алышпайт. Учурда сиз пайдаланып жаткан колдонмо дайындарды жөнөтүп/ала алат, бирок адаттагыдан азыраак өткөргөндүктөн, анын айрым функциялары талаптагыдай иштебей коюшу мүмкүн. Мисалы, сүрөттөр басылмайынча жүктөлбөйт."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Дайындарды үнөмдөгүч күйсүнбү?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Күйгүзүү"</string>
@@ -1783,14 +1786,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Өзгөчө кырдаалда жөнөтүлүүчү билдирүүлөрдү сыноо"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Жооп берүү"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM-картаны сүйлөшүү үчүн колдонууга тыюу салынган"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM-карта сүйлөшүү үчүн таанылган жок"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM-картаны сүйлөшүү үчүн колдонууга тыюу салынган"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Телефонду сүйлөшүү үчүн колдонууга тыюу салынган"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Калкып чыкма терезе"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Бул кыска жолго колдонмонун эң акыркы версиясы талап кылынат"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 79a41aa..3cf1d1e 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"ບໍ່ມີບໍລິການສຽງ/ສຸກເສີນ"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"ເຄືອຂ່າຍຂອງທ່ານບໍ່ໄດ້ໃຫ້ບໍລິການຢູ່ສະຖານທີ່ນີ້ເປັນການຊົ່ວຄາວ"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Can’t reach network"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"ເພື່ອປັບປຸງການຮັບສັນຍານ, ໃຫ້ລອງປ່ຽນປະເພດທີ່ເລືອກໄວ້ຢູ່ທີ່ ການຕັ້ງຄ່າ > ເຄືອຂ່າຍ ແລະ ອິນເຕີເນັດ > ເຄືອຂ່າຍມືຖື > ປະເພດເຄືອຂ່າຍທີ່ຕ້ອງການ."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"ເພື່ອປັບປຸງການຮັບສັນຍານ, ໃຫ້ລອງປ່ຽນປະເພດທີ່ເລືອກໄວ້ຢູ່ທີ່ ການຕັ້ງຄ່າ > ເຄືອຂ່າຍ ແລະ ອິນເຕີເນັດ > ເຄືອຂ່າຍມືຖື > ປະເພດເຄືອຂ່າຍທີ່ຕ້ອງການ."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"ການໂທ Wi‑Fi ເຮັດວຽກຢູ່"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"ການໂທສຸກເສີນຕ້ອງໃຊ້ການເຊື່ອມຕໍ່ເຄືອຂ່າຍ."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"ການເຕືອນ"</string>
@@ -263,7 +263,7 @@
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"ເຂົ້າຫາລາຍຊື່ຂອງທ່ານ"</string>
<string name="permgrouprequest_contacts" msgid="1601591667800538208">"ອະນຸຍາດ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ໃຫ້ເຂົ້າເຖິງລາຍຊື່ຜູ້ຕິດຕໍ່ຂອງທ່ານ"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"ສະຖານທີ່"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"ເຂົ້າເຖິງທີ່ຕັ້ງອຸປະກອນນີ້"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"ເຂົ້າເຖິງຂໍ້ມູນສະຖານທີ່ຂອງອຸປະກອນນີ້"</string>
<string name="permgrouprequest_location" msgid="8903573681261610809">"ອະນຸຍາດ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ໃຫ້ເຂົ້າເຖິງສະຖານທີ່ຂອງອຸປະກອນ"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"ປະຕິທິນ"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"ເຂົ້າຫາປະຕິທິນຂອງທ່ານ"</string>
@@ -979,16 +979,11 @@
<string name="inputMethod" msgid="1653630062304567879">"ຮູບແບບການປ້ອນຂໍ້ມູນ"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"ການເຮັດວຽກຂອງຂໍ້ຄວາມ"</string>
<string name="email" msgid="4560673117055050403">"ອີເມວ"</string>
- <!-- no translation found for dial (1253998302767701559) -->
- <skip />
- <!-- no translation found for map (6521159124535543457) -->
- <skip />
- <!-- no translation found for browse (1245903488306147205) -->
- <skip />
- <!-- no translation found for sms (4560537514610063430) -->
- <skip />
- <!-- no translation found for add_contact (7867066569670597203) -->
- <skip />
+ <string name="dial" msgid="1253998302767701559">"ໂທ"</string>
+ <string name="map" msgid="6521159124535543457">"ລະບຸບ່ອນຢູ່"</string>
+ <string name="browse" msgid="1245903488306147205">"ເປີດ"</string>
+ <string name="sms" msgid="4560537514610063430">"ຂໍ້ຄວາມ"</string>
+ <string name="add_contact" msgid="7867066569670597203">"ເພີ່ມ"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"ພື້ນທີ່ຈັດເກັບຂໍ້ມູນກຳລັງຈະເຕັມ"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ການເຮັດວຽກບາງຢ່າງຂອງລະບົບບາງອາດຈະໃຊ້ບໍ່ໄດ້"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ບໍ່ມີບ່ອນເກັບຂໍ້ມູນພຽງພໍສຳລັບລະບົບ. ກວດສອບໃຫ້ແນ່ໃຈວ່າທ່ານມີພື້ນທີ່ຫວ່າງຢ່າງໜ້ອຍ 250MB ແລ້ວລອງໃໝ່."</string>
@@ -998,7 +993,6 @@
<string name="cancel" msgid="6442560571259935130">"ຍົກເລີກ"</string>
<string name="yes" msgid="5362982303337969312">"ຕົກລົງ"</string>
<string name="no" msgid="5141531044935541497">"ຍົກເລີກ"</string>
- <string name="close" msgid="2318214661230355730">"ປິດ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ກະລຸນາຮັບຊາບ"</string>
<string name="loading" msgid="7933681260296021180">"ກຳລັງໂຫລດ..."</string>
<string name="capital_on" msgid="1544682755514494298">"ເປີດ"</string>
@@ -1055,10 +1049,11 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"ຂະໜາດ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ສະແດງຕະຫຼອດເວລາ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ເປີດການເຮັດວຽກນີ້ຄືນໄດ້ໃນ ການຕັ້ງຄ່າລະບົບ > ແອັບຯ > ດາວໂຫລດແລ້ວ"</string>
- <string name="top_app_killed_title" msgid="6814231368167994497">"ແອັບບໍ່ຕອບສະໜອງ"</string>
- <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ອາດກຳລັງໃຊ້ໜ່ວຍຄວາມຈຳຫຼາຍເກີນໄປ"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ຮອງຮັບການຕັ້ງຄ່າຂະໜາດສະແດງຜົນປັດຈຸບັນ ແລະ ອາດມີຄວາມຜິດພາດໄດ້."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ສະແດງທຸກເທື່ອ"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> ຖືກສ້າງມາສຳລັບ Android OS ເວີຊັນທີ່ບໍ່ສາມາດໃຊ້ຮ່ວມກັນໄດ້ ແລະ ອາດເຮັດວຽກຜິດປົກກະຕິ. ອາດມີແອັບເວີຊັນໃໝ່ກວ່າໃຫ້ດາວໂຫລດ."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"ສະແດງທຸກເທື່ອ"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"ກວດເບິ່ງອັບເດດ"</string>
<string name="smv_application" msgid="3307209192155442829">"ແອັບຯ <xliff:g id="APPLICATION">%1$s</xliff:g> (ໂປຣເຊສ <xliff:g id="PROCESS">%2$s</xliff:g>) ໄດ້ລະເມີດນະໂຍບາຍ StrictMode ທີ່ບັງຄັບໃຊ້ດ້ວຍໂຕເອງ."</string>
<string name="smv_process" msgid="5120397012047462446">"ໂປຣເຊສ <xliff:g id="PROCESS">%1$s</xliff:g> ລະເມີດນະໂຍບາຍບັງຄັບໃຊ້ເອງ StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"ກຳລັງອັບເກຣດ Android..."</string>
@@ -1124,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"ລົງຊື່ເຂົ້າເຄືອຂ່າຍ"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ບໍ່ມີການເຂົ້າເຖິງອິນເຕີເນັດ"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi ບໍ່ມີສັນຍານອິນເຕີເນັດ"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ແຕະເພື່ອເບິ່ງຕົວເລືອກ"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"ສະຫຼັບໄປໃຊ້ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ແລ້ວ"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"ອຸປະກອນຈະໃຊ້ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ເມື່ອ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ. ອາດມີການຮຽກເກັບຄ່າບໍລິການ."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"ອຸປະກອນຈະໃຊ້ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ເມື່ອ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ. ອາດມີການຮຽກເກັບຄ່າບໍລິການ."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"ສະຫຼັບຈາກ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ໄປໃຊ້ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ແລ້ວ"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"ອິນເຕີເນັດມືຖື"</item>
@@ -1138,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ບໍ່ຮູ້ຈັກປະເພດເຄືອຂ່າຍ"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ບໍ່ສາມາດເຊື່ອມຕໍ່ Wi-Fi ໄດ້"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ມີສັນຍານອິນເຕີເນັດທີ່ບໍ່ດີ."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດທີ່ຊ້າ."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"ອະນຸຍາດການເຊື່ອມຕໍ່ຫຼືບໍ່?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"ແອັບພລິເຄຊັນ %1$s ຢາກຈະເຊື່ອມຕໍ່ກັບເຄືອຂ່າຍ Wifi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"ແອັບພລິເຄຊັນ"</string>
@@ -1634,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"ບ່ອນເຮັດວຽກທີ 2 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"ບ່ອນເຮັດວຽກທີ 3 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"ເພື່ອຍົກເລີກການປັກໝຸດໜ້າຈໍນີ້, ໃຫ້ແຕະປຸ່ມກັບຄືນ ແລະ ປຸ່ມພາບຮວມຄ້າງໄວ້"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"ບໍ່ສາມາດຍົກເລີກການປັກໝຸນແອັບນີ້ໄດ້"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"ປັກໝຸດໜ້າຈໍແລ້ວ"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"ຍົກເລີກການປັກໝຸນຫນ້າຈໍແລ້ວ"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ຖາມຫາ PIN ກ່ອນຍົກເລີກການປັກໝຸດ"</string>
@@ -1643,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"ຖືກຕິດຕັ້ງໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"ຖືກອັບໂຫລດໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"ຖືກລຶບອອກໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"ເພື່ອຊ່ວຍເພີ່ມອາຍຸແບັດເຕີຣີ, ຕົວປະຢັດໄຟແບັດເຕີຣີຫຼຸດປະສິດທິພາບການເຮັດວຽກຂອງອຸປະກອນຂອງທ່ານລົງ ແລະຈຳກັດການສັ່ນ, ບໍລິການສະຖານທີ່ ແລະ ຂໍ້ມູນພື້ນຫຼັງເກືອບທັງໝົດ. ອີເມວ, ການສົ່ງຂໍ້ຄວາມ ແລະ ແອັບອື່ນໆທີ່ອາໄສການຊິ້ງຂໍ້ມູນອາດຈະບໍ່ອັບເດດ ນອກຈາກວ່າທ່ານເປີດມັນ.\n\nຕົວປະຢັດໄຟແບັດເຕີຣີຈະປິດອັດຕະໂນມັດເມື່ອທ່ານສາກໄຟອຸປະກອນ."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"ເພື່ອຊ່ວຍເພີ່ມອາຍຸແບັດເຕີຣີ, ຕົວປະຢັດໄຟແບັດເຕີຣີຫຼຸດປະສິດທິພາບການເຮັດວຽກຂອງອຸປະກອນຂອງທ່ານລົງ ແລະຈຳກັດການສັ່ນ, ການບໍລິການຫາທີ່ຕັ້ງ, ແລະຂໍ້ມູນພື້ນຫຼັງເກືອບທັງໝົດ. ອີເມວ, ການສົ່ງຂໍ້ຄວາມ, ແລະແອັບອື່ນໆທີ່ອາໄສການຊິງຄ໌ອາດຈະບໍ່ອັບເດດ ນອກຈາກວ່າທ່ານເປີດມັນ.\n\nຕົວປະຢັດແບັດເຕີຣີຈະປິດອັດຕະໂນມັດ ເມື່ອອຸປະກອນຂອງທ່ານກຳລັງສາກຢູ່."</string>
<string name="data_saver_description" msgid="6015391409098303235">"ເພື່ອຊ່ວຍຫຼຸດຜ່ອນການນຳໃຊ້ຂໍ້ມູນ, ຕົວປະຢັດຂໍ້ມູນຈະປ້ອງກັນບໍ່ໃຫ້ບາງແອັບສົ່ງ ຫຼື ຮັບຂໍ້ມູນໃນພື້ນຫຼັງ. ແອັບໃດໜຶ່ງທີ່ທ່ານກຳລັງໃຊ້ຢູ່ຈະສາມາດເຂົ້າເຖິງຂໍ້ມູນໄດ້ ແຕ່ອາດເຂົ້າເຖິງໄດ້ຖີ່ໜ້ອຍລົງ. ນີ້ອາດໝາຍຄວາມວ່າ ຮູບພາບຕ່າງໆອາດບໍ່ສະແດງຈົນກວ່າທ່ານຈະແຕະໃສ່ກ່ອນ."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ເປີດໃຊ້ຕົວປະຢັດຂໍ້ມູນບໍ?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ເປີດໃຊ້"</string>
@@ -1790,18 +1784,14 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"ທົດສອບຂໍ້ຄວາມສຸກເສີນ"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"ຕອບກັບ"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <string name="mmcc_authentication_reject" msgid="7729819349669603406">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ SIM"</string>
- <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"ບໍ່ມີການນຳໃຊ້ SIM"</string>
- <string name="mmcc_illegal_ms" msgid="2769452751852211112">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ SIM"</string>
- <string name="mmcc_illegal_me" msgid="4438696681169345015">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ໂທລະສັບ"</string>
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ຊິມສຳລັບການໂທສຽງ"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"ບໍ່ໄດ້ຈັດກຽມຊິມໄວ້ສຳລັບການໂທສຽງ"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ຊິມສຳລັບການໂທສຽງ"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ໂທລະສັບສຳລັບການໂທສຽງ"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"ໜ້າຈໍປັອບອັບ"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
- <!-- no translation found for shortcut_restored_on_lower_version (5270675146351613828) -->
- <skip />
- <!-- no translation found for shortcut_restore_not_supported (5028808567940014190) -->
- <skip />
- <!-- no translation found for shortcut_restore_signature_mismatch (2406209324521327518) -->
- <skip />
- <!-- no translation found for shortcut_restore_unknown_issue (8703738064603262597) -->
- <skip />
+ <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"ທາງລັດນີ້ຕ້ອງໃຊ້ແອັບເວີຊັນຫຼ້າສຸດ"</string>
+ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"ບໍ່ສາມາດກູ້ທາງລັດຂຶ້ນມາໄດ້ເນື່ອງຈາກແອັບບໍ່ຮອງຮັບການສຳຮອງ ແລະ ກູ້ຂໍ້ມູນ"</string>
+ <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ບໍ່ສາມາດກູ້ທາງລັດຄືນມາໄດ້ເນື່ອງຈາກລາຍເຊັນແອັບບໍ່ກົງກັນ"</string>
+ <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"ບໍ່ສາມາດກູ້ທາງລັດຄືນມາໄດ້"</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index c836374..e0d9771 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -81,7 +81,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Balso skambučių / skambučių pagalbos numeriais paslauga neteikiama"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Laikinai nesiūloma mobiliojo ryšio tinkle jūsų vietovėje"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Nepavyko pasiekti tinklo"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Kad pagerintumėte ryšį, pabandykite pakeisti tipą, pasirinktą skiltyje „Nustatymai“ > „Tinklas ir internetas“ > „Mobiliojo ryšio tinklai“ > „Pageidaujamas tinklo tipas“."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Kad pagerintumėte ryšį, pabandykite pakeisti tipą, pasirinktą skiltyje „Nustatymai“ > „Tinklas ir internetas“ > „Mobiliojo ryšio tinklai“ > „Pageidaujamas tinklo tipas“."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"„Wi-Fi“ skambinimas aktyvus"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Kad būtų galima skambinti pagalbos numeriais, būtina naudoti mobiliojo ryšio tinklą."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Įspėjimai"</string>
@@ -1091,6 +1091,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Įgalinkite jį iš naujo nuėję į „Sistemos nustatymai“ > „Programos“ > „Atsisiųsta“."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Programoje „<xliff:g id="APP_NAME">%1$s</xliff:g>“ nepalaikomas dabartinis ekrano dydžio nustatymas ir ji gali netinkamai veikti."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Visada rodyti"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ buvo sukurta nesuderinamos versijos „Android“ OS ir gali netinkamai veikti. Gali būti pasiekiama atnaujintos versijos programa."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Visada rodyti"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Tikrinti, ar yra naujinių"</string>
<string name="smv_application" msgid="3307209192155442829">"Programa „<xliff:g id="APPLICATION">%1$s</xliff:g>“ (procesas „<xliff:g id="PROCESS">%2$s</xliff:g>“) pažeidė savo vykdomą „StrictMode“ politiką."</string>
<string name="smv_process" msgid="5120397012047462446">"„<xliff:g id="PROCESS">%1$s</xliff:g>“ procesas pažeidė savo vykdomą „StrictMode“ politiką."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"„Android“ naujovinama..."</string>
@@ -1160,10 +1163,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Prisijungti prie tinklo"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"„Wi-Fi“ tinkle nėra interneto ryšio"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"„Wi‑Fi“ tinkle nėra interneto ryšio"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Palieskite, kad būtų rodomos parinktys."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Perjungta į tinklą <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Įrenginys naudoja tinklą <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kai tinkle <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nėra interneto ryšio. Gali būti taikomi mokesčiai."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Įrenginyje naudojamas kitas tinklas (<xliff:g id="NEW_NETWORK">%1$s</xliff:g>), kai dabartiniame tinkle (<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>) nėra interneto ryšio. Gali būti taikomi mokesčiai."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Perjungta iš tinklo <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> į tinklą <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobiliojo ryšio duomenys"</item>
@@ -1174,7 +1177,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nežinomas tinklo tipas"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nepavyko prisijungti prie „Wi-Fi“"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" turi prastą interneto ryšį."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" turi prastą interneto ryšį."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Leisti prisijungti?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Programa „%1$s“ nori prisijungti prie „Wi-Fi“ tinklo „%2$s“"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Programa"</string>
@@ -1676,7 +1679,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2-asis darbo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3-iasis darbo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Kad atsegtumėte šį ekraną, palieskite ir palaikykite mygtukus „Atgal“ ir „Apžvalga“"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Šios programos negalima atsegti"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Ekrano prisegtas"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Ekranas atsegtas"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Prašyti PIN kodo prieš atsegant"</string>
@@ -1685,7 +1687,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Įdiegė administratorius"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Atnaujino administratorius"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Ištrynė administratorius"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Kad tausotų akumuliatoriaus energiją, akumuliatoriaus tausojimo priemonė sumažina įrenginio veikimą ir apriboja vibravimą, vietovės paslaugas bei daugumą foninių duomenų. El. pašto, susirašinėjimo ir kitos programos, kurios veikia sinchronizavimo pagrindu, gali būti neatnaujintos, nebent jas atidarysite.\n\nAkumuliatoriaus tausojimo priemonė automatiškai išjungiama, kai įrenginys įkraunamas."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Kad pailgintų akumuliatoriaus naudojimo laiką, Akumuliatoriaus tausojimo priemonė sumažina įrenginio veikimą ir apriboja vibravimą, vietovės paslaugas bei daugumą foninių duomenų. El. pašto, susirašinėjimo ir kitos programos, kurios veikia sinchronizavimo pagrindu, gali būti neatnaujintos, nebent jas atidarysite.\n\nAkumuliatoriaus tausojimo priemonė automatiškai išjungiama, kai įrenginys įkraunamas."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Kad padėtų sumažinti duomenų naudojimą, Duomenų taupymo priemonė neleidžia kai kurioms programoms siųsti ar gauti duomenų fone. Šiuo metu naudojama programa gali pasiekti duomenis, bet tai bus daroma rečiau. Tai gali reikšti, kad, pvz., vaizdai nebus pateikiami, jei jų nepaliesite."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Įj. Duomenų taupymo priemonę?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Įjungti"</string>
@@ -1852,14 +1854,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Kritinės padėties pranešimo bandymas"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Atsakyti"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM kortelė neleidžiama naudojant balso paslaugas"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM kortelė neteikiama naudojant balso paslaugas"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM kortelė neleidžiama naudojant balso paslaugas"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefonas neleidžiamas naudojant balso paslaugas"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Iššokantysis langas"</string>
<string name="slice_more_content" msgid="8504342889413274608">"Dar <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Norint naudoti šį spartųjį klavišą būtina naujausios versijos programa"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 9a067c6..573baf3 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -80,7 +80,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Balss un ārkārtas izsaukumu pakalpojums nedarbojas"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Pagaidām netiek piedāvāts mobilajā tīklā jūsu atrašanās vietā"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Nevar sasniegt tīklu"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Lai uzlabotu uztveršanu, mainiet atlasīto veidu sadaļā Iestatījumi > Tīkls un internets > Mobilie tīkli > Ieteicamais tīkla veids."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Lai uzlabotu uztveršanu, mainiet atlasīto veidu sadaļā Iestatījumi > Tīkls un internets > Mobilie tīkli > Ieteicamais tīkla veids."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi zvani ir aktīvi"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Lai veiktu ārkārtas zvanus, ir nepieciešams mobilais tīkls."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Brīdinājumi"</string>
@@ -1071,6 +1071,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Atkārtoti iespējojiet šeit: Sistēmas iestatījumi > Lietotnes > Lejupielādētās."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g> netiek atbalstīts pašreizējais displeja lieluma iestatījums, tādēļ tā var tikt attēlota neparedzētā veidā."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Rādīt vienmēr"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> tika izstrādāta nesaderīgai Android OS versijai, tādēļ tā var darboties neparedzētā veidā. Iespējams, ir pieejama atjaunināta lietotnes versija."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Vienmēr rādīt"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Pārbaudīt, vai ir pieejams atjauninājums"</string>
<string name="smv_application" msgid="3307209192155442829">"Lietotne <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) ir pārkāpusi savu pašieviesto StrictMode politiku."</string>
<string name="smv_process" msgid="5120397012047462446">"Process <xliff:g id="PROCESS">%1$s</xliff:g> ir pārkāpis savu pašieviesto StrictMode politiku."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Notiek Android jaunināšana..."</string>
@@ -1138,10 +1141,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Pierakstīšanās tīklā"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi tīklā nav piekļuves internetam."</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi tīklā nav piekļuves internetam."</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Pieskarieties, lai skatītu iespējas."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Pārslēdzās uz tīklu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Kad tīklā <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nav piekļuves internetam, ierīcē tiek izmantots tīkls <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Var tikt piemērota maksa."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Kad vienā tīklā (<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>) nav piekļuves internetam, ierīcē tiek izmantots cits tīkls (<xliff:g id="NEW_NETWORK">%1$s</xliff:g>). Var tikt piemērota maksa."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Pārslēdzās no tīkla <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> uz tīklu <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobilie dati"</item>
@@ -1152,7 +1155,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nezināms tīkla veids"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nevarēja izveidot savienojumu ar Wi-Fi."</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ir slikts interneta savienojums."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ir slikts interneta savienojums."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vai atļaut savienojumu?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Lietotne %1$s vēlas izveidot savienojumu ar Wi-Fi tīklu %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Lietojumprogramma"</string>
@@ -1651,7 +1654,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. darba profils: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. darba profils: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Lai atspraustu šo ekrānu, pieskarieties pogām “Atpakaļ” un “Pārskats” un turiet tās."</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Šo lietotni nevar atspraust."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Ekrāns ir piesprausts"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Ekrāns ir atsprausts"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Prasīt PIN kodu pirms atspraušanas"</string>
@@ -1660,7 +1662,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Instalēja administrators"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Atjaunināja administrators"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Dzēsa administrators"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Lai paildzinātu akumulatora darbību, akumulatora jaudas taupīšanas režīmā tiek samazināta ierīces veiktspēja un tiek ierobežota vibrācija, atrašanās vietu pakalpojumi un lielākā daļa fona datu. E-pasta, ziņojumapmaiņas un cita veida lietotnes, kuru darbības pamatā ir datu sinhronizācija, var netikt atjauninātas, ja tās neatverat.\n\nTiklīdz tiek sākta ierīces uzlāde, akumulatora jaudas taupīšanas režīms automātiski tiek izslēgts."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Lai paildzinātu akumulatora darbību, akumulatora jaudas taupīšanas režīmā tiek samazināta ierīces veiktspēja un tiek ierobežota vibrācija, atrašanās vietu pakalpojumi un lielākā daļa fona datu. E-pasta, ziņojumapmaiņas un citas lietotnes, kurām ir nepieciešama sinhronizācija, var netikt atjauninātas, ja tās neatverat.\n\nTiklīdz tiek sākta ierīces uzlāde, akumulatora jaudas taupīšanas režīms tiek automātiski izslēgts."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Lai samazinātu datu lietojumu, datu lietojuma samazinātājs neļauj dažām lietotnēm fonā nosūtīt vai saņemt datus. Lietotne, kuru pašlaik izmantojat, var piekļūt datiem, bet, iespējams, piekļūs tiem retāk (piemēram, attēli tiks parādīti tikai tad, kad tiem pieskarsieties)."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Vai ieslēgt datu lietojuma samazinātāju?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Ieslēgt"</string>
@@ -1817,14 +1819,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Ārkārtas ziņojuma pārbaude"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Atbildēt"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM karti nav atļauts izmantot balss zvaniem"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM kartē netiek nodrošināti balss zvani"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM karti nav atļauts izmantot balss zvaniem"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Tālruni nav atļauts izmantot balss zvaniem"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Uznirstošais logs"</string>
<string name="slice_more_content" msgid="8504342889413274608">"Vēl <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Šai saīsnei ir nepieciešama jaunākā lietotne."</string>
diff --git a/core/res/res/values-mcc310-mnc030-da/strings.xml b/core/res/res/values-mcc310-mnc030-da/strings.xml
index dab4912..c45e3be 100644
--- a/core/res/res/values-mcc310-mnc030-da/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-da/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM-kort leveres ikke MM#2"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM-kortet er ikke aktiveret MM#2"</string>
<string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM-kort er ikke tilladt MM#3"</string>
<string name="mmcc_illegal_me" msgid="2995576894416087107">"Telefonen har ikke adgangstilladelse MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc170-da/strings.xml b/core/res/res/values-mcc310-mnc170-da/strings.xml
index 98ab336..8580fb3 100644
--- a/core/res/res/values-mcc310-mnc170-da/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-da/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM-kort leveres ikke MM#2"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM-kortet er ikke aktiveret MM#2"</string>
<string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM-kort er ikke tilladt MM#3"</string>
<string name="mmcc_illegal_me" msgid="3173546391131606065">"Telefonen har ikke adgangstilladelse MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc280-da/strings.xml b/core/res/res/values-mcc310-mnc280-da/strings.xml
index 180c523..6a8e40b 100644
--- a/core/res/res/values-mcc310-mnc280-da/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-da/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM-kort leveres ikke MM#2"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM-kortet er ikke aktiveret MM#2"</string>
<string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM-kort er ikke tilladt MM#3"</string>
<string name="mmcc_illegal_me" msgid="822496463303720579">"Telefonen har ikke adgangstilladelse MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc380-da/strings.xml b/core/res/res/values-mcc310-mnc380-da/strings.xml
index 7dda72c..cd4c796 100644
--- a/core/res/res/values-mcc310-mnc380-da/strings.xml
+++ b/core/res/res/values-mcc310-mnc380-da/strings.xml
@@ -20,6 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="6933439408719203102">"SIM-kort leveres ikke MM#2"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="6933439408719203102">"SIM-kortet er ikke aktiveret MM#2"</string>
<string name="mmcc_illegal_ms" msgid="6367773216941648568">"SIM-kort er ikke tilladt MM#3"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc410-da/strings.xml b/core/res/res/values-mcc310-mnc410-da/strings.xml
index 38c47b3..3c5b9ee 100644
--- a/core/res/res/values-mcc310-mnc410-da/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-da/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM-kort leveres ikke MM#2"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM-kortet er ikke aktiveret MM#2"</string>
<string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM-kort er ikke tilladt MM#3"</string>
<string name="mmcc_illegal_me" msgid="4477688981805467729">"Telefonen har ikke adgangstilladelse MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc560-da/strings.xml b/core/res/res/values-mcc310-mnc560-da/strings.xml
index 857e040..95c214b 100644
--- a/core/res/res/values-mcc310-mnc560-da/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-da/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM-kort leveres ikke MM#2"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM-kortet er ikke aktiveret MM#2"</string>
<string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM-kort er ikke tilladt MM#3"</string>
<string name="mmcc_illegal_me" msgid="7030488670186895244">"Telefonen har ikke adgangstilladelse MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc950-da/strings.xml b/core/res/res/values-mcc310-mnc950-da/strings.xml
index e63a586..97c801b 100644
--- a/core/res/res/values-mcc310-mnc950-da/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-da/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM-kort leveres ikke MM#2"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM-kortet er ikke aktiveret MM#2"</string>
<string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM-kort er ikke tilladt MM#3"</string>
<string name="mmcc_illegal_me" msgid="8920048244573695129">"Telefonen har ikke adgangstilladelse MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc311-mnc180-da/strings.xml b/core/res/res/values-mcc311-mnc180-da/strings.xml
index 6fadac1..5bcc43d 100644
--- a/core/res/res/values-mcc311-mnc180-da/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-da/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM-kort leveres ikke MM#2"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM-kortet er ikke aktiveret MM#2"</string>
<string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM-kort er ikke tilladt MM#3"</string>
<string name="mmcc_illegal_me" msgid="5766888847785331904">"Telefonen har ikke adgangstilladelse MM#6"</string>
</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 1deac5d..d3fa3d1 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Нема услуга за говорни/итни повици"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Привремено не се нуди од мобилната мрежа на вашата локација"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Не може да се дојде до мрежата"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"За подобрување на приемот, обидете се да го промените избраниот тип во „Поставки > Мрежа и интернет > Мобилни мрежи > Претпочитан тип мрежа“."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"За подобрување на приемот, обидете се да го промените избраниот тип во „Поставки > Мрежа и интернет > Мобилни мрежи > Претпочитан тип мрежа“."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"„Повикување преку Wi‑Fi“ е активна"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"За итните повици е потребна мобилна мрежа."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Предупредувања"</string>
@@ -984,7 +984,7 @@
<string name="browse" msgid="1245903488306147205">"Отвори"</string>
<string name="sms" msgid="4560537514610063430">"Порака"</string>
<string name="add_contact" msgid="7867066569670597203">"Додај"</string>
- <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Меморијата е речиси полна"</string>
+ <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Капацитетот е речиси полн"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некои системски функции може да не работат"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Нема доволно меморија во системот. Проверете дали има слободен простор од 250 МБ и рестартирајте."</string>
<string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> работи"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Повторно овозможете го ова во Системски поставки > Апликации > Преземено."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не ја поддржува тековната поставка за големина на екранот и може да се однесува непредвидено."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Секогаш прикажувај"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> е создадена за некомпатибилна верзија на Android OS и може да се однесува непредвидливо. Можеби е достапна ажурирана верзија на апликацијата."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Секогаш прикажувај"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Провери за ажурирање"</string>
<string name="smv_application" msgid="3307209192155442829">"Апликацијата <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) ја прекрши политиката StrictMode што си ја наметна врз себеси."</string>
<string name="smv_process" msgid="5120397012047462446">"Процесот <xliff:g id="PROCESS">%1$s</xliff:g> ја прекрши својата самонаметната политика на строг режим."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android се ажурира…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Најавете се на мрежа"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi нема пристап на интернет"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi нема пристап до интернет"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Допрете за опции"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Префрлено на <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Уредот користи <xliff:g id="NEW_NETWORK">%1$s</xliff:g> кога <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема пристап до интернет. Може да се наплатат трошоци."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Уредот користи <xliff:g id="NEW_NETWORK">%1$s</xliff:g> кога <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема пристап до интернет. Може да се наплатат трошоци."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Префрлено од <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"мобилен интернет"</item>
@@ -1130,7 +1133,8 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"непознат тип мрежа"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не можеше да се поврзе со Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има слаба конекција на интернет."</string>
+ <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+ <skip />
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дозволете поврзување?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Апликацијата %1$s сака да се поврзе со Wifi-мрежата %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Апликација"</string>
@@ -1628,7 +1632,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Втора деловна <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Трета деловна <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"За откачување на екранов, допрете и задржете ги копчињата „Назад“ и „Краток преглед“."</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Апликацијава не може да се откачи"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Екранот е закачен"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Екранот е откачен"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Прашај за PIN пред откачување"</string>
@@ -1637,7 +1640,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Инсталирано од администраторот"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Ажурирано од администраторот"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Избришано од администраторот"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"За да ви помогне да ја подобрите трајноста на батеријата, штедачот на батеријата ја намалува изведбата на уредот и го ограничува вибрирањето, услугите за локација и повеќето податоци во заднина. Е-поштата, испраќањето пораки и другите апликации што користат синхронизација можеби нема да се ажурираат доколку не ги отворите.\n\nШтедачот на батеријата автоматски се исклучува кога уредот се полни."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"За да ви помогне да ја подобрите трајноста на батеријата, штедачот на батеријата ја намалува изведбата на уредот и ги ограничува вибрациите, услугите за локација и повеќето податоци од заднина. Е-пошта, Пораки и другите апликации што користат синхронизација можеби нема да се ажурираат ако не ги отворите.\n\nШтедачот на батеријата автоматски се исклучува кога уредот се полни."</string>
<string name="data_saver_description" msgid="6015391409098303235">"За да се намали користењето интернет, Штедачот на интернет спречува дел од апликациите да испраќаат или да примаат податоци во заднина. Апликацијата што ја користите во моментов можеби ќе пристапува до интернет, но тоа ќе го прави поретко. Ова значи, на пример, дека сликите нема да се прикажат додека не ги допрете."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Вклучете Штедач на интернет?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Вклучи"</string>
@@ -1784,14 +1787,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Тестирање пораки за итни случаи"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Одговори"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"Не е дозволена SIM-картичка за глас"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"Не е обезбедена SIM-картичка за глас"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"Не е дозволена SIM-картичка за глас"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Не е дозволен телефон за глас"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Појавен прозорец"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"За кратенкава е потребна најновата апликација"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 8fb570b..5f9f137 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"വോയ്സ്/അടിയന്തിര സേവനമില്ല"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"നിങ്ങളുടെ ലൊക്കേഷനിൽ മൊബൈൽ നെറ്റ്വര്ക്ക് താൽക്കാലികമായി ലഭ്യമല്ല"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"നെറ്റ്വർക്കിലേക്ക് കണക്റ്റുചെയ്യാനാവുന്നില്ല"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"സ്വീകരണം മെച്ചപ്പെടുത്തുന്നതിന് സിസ്റ്റം > നെറ്റ്വർക്കും ഇന്റെർനെറ്റും > മൊബൈൽ നെറ്റ്വർക്കുകൾ > തിരഞ്ഞെടുത്ത നെറ്റ്വർക്ക് തരം എന്നതിൽ തിരഞ്ഞെടുത്തിരിക്കുന്ന തരം മാറ്റിക്കൊണ്ട് ശ്രമിച്ചുനോക്കുക."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"റിസപ്ഷൻ മെച്ചപ്പെടുത്താൻ, ക്രമീകരണം > നെറ്റ്വർക്കും ഇന്റർനെറ്റും > മൊബൈൽ നെറ്റ്വർക്കുകൾ > തിരഞ്ഞെടുത്ത നെറ്റ്വർക്ക് തരം എന്നതിൽ തിരഞ്ഞെടുത്തിരിക്കുന്ന തരം മാറ്റുന്നത് പരീക്ഷിക്കുക."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"വൈ-ഫൈ കോളിംഗ് സജീവമാണ്"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"എമർജൻസി കോളുകൾ ചെയ്യാൻ ഒരു മൊബൈൽ നെറ്റ്വർക്ക് ആവശ്യമാണ്."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"അലേർട്ടുകൾ"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"സിസ്റ്റം ക്രമീകരണങ്ങൾ > അപ്ലിക്കേഷനുകൾ > ഡൗൺലോഡുചെയ്തവ എന്നതിൽ ഇത് വീണ്ടും പ്രവർത്തനക്ഷമമാക്കുക."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"നിലവിലെ ഡിസ്പ്ലേ വലുപ്പ ക്രമീകരണത്തെ <xliff:g id="APP_NAME">%1$s</xliff:g> പിന്തുണയ്ക്കുന്നില്ല, അതിനാൽ പ്രതീക്ഷിക്കാത്ത തരത്തിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കാം."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"എല്ലായ്പ്പോഴും ദൃശ്യമാക്കുക"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> നിർമ്മിച്ചിരിക്കുന്നത് Android OS-ന്റെ അനുയോജ്യമല്ലാത്ത പതിപ്പിന് വേണ്ടിയായതിനാൽ ഇത് പ്രതീക്ഷിക്കാത്ത തരത്തിൽ പ്രവർത്തിക്കാനിടയുണ്ട്. ആപ്പിന്റെ അപ്ഡേറ്റ് ചെയ്ത പതിപ്പ് ലഭ്യമായേക്കാം."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"എപ്പോഴും കാണിക്കുക"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"അപ്ഡേറ്റിനായി പരിശോധിക്കുക"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> എന്ന അപ്ലിക്കേഷൻ (<xliff:g id="PROCESS">%2$s</xliff:g> പ്രോസസ്സ്) അതിന്റെ സ്വയം നിർബന്ധിത StrictMode നയം ലംഘിച്ചു."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> എന്ന പ്രോസസ്സ് അതിന്റെ സ്വയം നടപ്പിലാക്കിയ StrictMode നയം ലംഘിച്ചു."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android അപ്ഗ്രേഡുചെയ്യുന്നു…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"നെറ്റ്വർക്കിലേക്ക് സൈൻ ഇൻ ചെയ്യുക"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-യിൽ ഇന്റർനെറ്റ് ആക്സസ് ഇല്ല."</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"വൈഫൈയ്ക്ക് ഇന്റർനെറ്റ് ആക്സസ് ഇല്ല"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ഓപ്ഷനുകൾക്ക് ടാപ്പുചെയ്യുക"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> എന്നതിലേക്ക് മാറി"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> നെറ്റ്വർക്കിന് ഇന്റർനെറ്റ് ആക്സസ്സ് ഇല്ലാത്തപ്പോൾ ഉപകരണം <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ഉപയോഗിക്കുന്നു. നിരക്കുകൾ ബാധകമായേക്കാം."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>-ന് ഇന്റർനെറ്റ് ആക്സസ് ഇല്ലാത്തപ്പോൾ ഉപകരണം <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ഉപയോഗിക്കുന്നു. നിരക്കുകൾ ബാധകമായേക്കാം."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> നെറ്റ്വർക്കിൽ നിന്ന് <xliff:g id="NEW_NETWORK">%2$s</xliff:g> നെറ്റ്വർക്കിലേക്ക് മാറി"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"മൊബൈൽ ഡാറ്റ"</item>
@@ -1130,7 +1133,8 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"തിരിച്ചറിയാനാകാത്ത ഒരു നെറ്റ്വർക്ക് തരം"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-ലേക്ക് കണക്റ്റുചെയ്യാൻ കഴിഞ്ഞില്ല"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" മോശം ഇന്റർനെറ്റ് കണക്ഷനാണുള്ളത്."</string>
+ <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+ <skip />
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"കണക്ഷൻ അനുവദിക്കണോ?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"അപ്ലിക്കേഷൻ %1$s Wifi നെറ്റ്വർക്കിലേക്ക് കണക്റ്റുചെയ്യാൻ താൽപ്പര്യപ്പെടുന്നു %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"ഒരു അപ്ലിക്കേഷൻ"</string>
@@ -1634,7 +1638,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"നിങ്ങളുടെ അഡ്മിൻ ഇൻസ്റ്റാൾ ചെയ്യുന്നത്"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"നിങ്ങളുടെ അഡ്മിൻ അപ്ഡേറ്റ് ചെയ്യുന്നത്"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"നിങ്ങളുടെ അഡ്മിൻ ഇല്ലാതാക്കുന്നത്"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"ബാറ്ററി ആയുസ്സ് മെച്ചപ്പെടുത്താൻ സഹായിക്കുന്നതിന്, ബാറ്ററി ലാഭിക്കൽ നിങ്ങളുടെ ഉപകരണത്തിന്റെ പ്രകടനത്തെ കുറയ്ക്കുകയും വൈബ്രേഷൻ, പ്രദേശ സർവീസുകൾ, ഒട്ടുമിക്ക പശ്ചാത്തല ഡാറ്റകൾ എന്നിവയെ പരിമിതപ്പെടുത്തുകയും ചെയ്യുന്നു. സമന്വയത്തെ ആശ്രയിച്ചുള്ള ഇമെയിൽ, സന്ദേശമയയ്ക്കൽ, മറ്റു ആപ്പുകൾ എന്നിവ തുറക്കാത്ത പക്ഷം അപ്ഡേറ്റാകാൻ സാധ്യതയില്ല.\n\n നിങ്ങളുടെ ഉപകരണം ചാർജ്ജ് ചെയ്യുമ്പോൾ ബാറ്ററി ലാഭിക്കൽ സ്വയം ഓഫാകും."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"ബാറ്ററി ആയുസ്സ് മെച്ചപ്പെടുത്താൻ സഹായിക്കുന്നതിന്, ബാറ്ററി ലാഭിക്കൽ ഉപകരണത്തിന്റെ പ്രകടനത്തെ കുറയ്ക്കുകയും വൈബ്രേഷൻ, ലൊക്കേഷൻ സേവനങ്ങൾ, ഭൂരിഭാഗം പശ്ചാത്തല ഡാറ്റ എന്നിവയെ പരിമിതപ്പെടുത്തുകയും ചെയ്യുന്നു. സമന്വയത്തെ ആശ്രയിച്ചുള്ള ഇമെയിൽ, സന്ദേശമയയ്ക്കൽ, മറ്റ് ആപ്പുകൾ എന്നിവ തുറക്കാത്ത പക്ഷം അപ്ഡേറ്റാകാൻ സാധ്യതയില്ല.\n\nനിങ്ങളുടെ ഉപകരണം ചാർജ് ചെയ്യുമ്പോൾ ബാറ്ററി ലാഭിക്കൽ സ്വയം ഓഫാകും."</string>
<string name="data_saver_description" msgid="6015391409098303235">"ഡാറ്റാ ഉപയോഗം കുറയ്ക്കാൻ സഹായിക്കുന്നതിന്, പശ്ചാത്തലത്തിൽ ഡാറ്റ അയയ്ക്കുകയോ സ്വീകരിക്കുകയോ ചെയ്യുന്നതിൽ നിന്ന് ചില ആപ്സിനെ ഡാറ്റ സേവർ തടയുന്നു. നിങ്ങൾ നിലവിൽ ഉപയോഗിക്കുന്ന ഒരു ആപ്പിന് ഡാറ്റ ആക്സസ്സ് ചെയ്യാൻ കഴിയും, എന്നാൽ കുറഞ്ഞ ആവൃത്തിയിലാണിത് നടക്കുക. ഇതിനർത്ഥം, നിങ്ങൾ ടാപ്പുചെയ്യുന്നത് വരെ ചിത്രങ്ങൾ കാണിക്കുകയില്ല എന്നാണ്."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ഡാറ്റ സേവർ ഓണാക്കണോ?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ഓണാക്കുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 3e1992b..16681dc 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Дуу хоолой/яаралтай үйлчилгээ алга"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Таны байршилд таны мобайл сүлжээнээс түр хугацаанд блоклосон"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Сүлжээнд холбогдох боломжгүй байна"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Хүлээн авалтыг сайжруулахын тулд Тохиргоо > Сүлжээ & Интернэт > Мобайл сүлжээ > Сонгосон сүлжээний төрөл хэсгийг сонгон төрлөө өөрчилнө үү."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Хүлээн авалтыг сайжруулахын тулд Тохиргоо > Сүлжээ & Интернет > Мобайл сүлжээ > Сонгосон сүлжээний төрөл хэсэгт сонгосон төрлөө өөрчилнө үү."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi дуудлага идэвхтэй байна"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Яаралтай дуудлага хийхэд мобайл сүлжээнд холбогдсон байх шаардлагатай."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Сануулга"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Энийг Системийн тохиргоо > Апп > Татаж авсан дотроос дахин идэвхтэй болгох боломжтой."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь Дэлгэцийн хэмжээний одоогийн тохиргоог дэмждэггүй учир буруу ажиллаж болзошгүй."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Байнга харуулах"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г Андройдын үйлдлийн системийн тохирохгүй хувилбарт зориулсан бөгөөд буруу ажиллаж болзошгүй. Аппын шинэчилсэн хувилбар боломжтой."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Тогтмол харуулах"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Шинэчлэлтийг шалгах"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> апп (<xliff:g id="PROCESS">%2$s</xliff:g> процесс) өөрийнхөө StrictMode бодлогыг зөрчив."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> процесс өөрийнхөө StrictMode бодлогыг зөрчив."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Андройдыг дэвшүүлж байна…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Сүлжээнд нэвтэрнэ үү"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-д интернет холболт байхгүй байна"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi-д интернет хандалт алга"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Сонголт хийхийн тулд товшино уу"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> руу шилжүүлсэн"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> интернэт холболтгүй үед төхөөрөмж <xliff:g id="NEW_NETWORK">%1$s</xliff:g>-г ашигладаг. Төлбөр гарч болзошгүй."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> интернет холболтгүй үед төхөөрөмж <xliff:g id="NEW_NETWORK">%1$s</xliff:g>-г ашигладаг. Төлбөр гарч болзошгүй."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-с <xliff:g id="NEW_NETWORK">%2$s</xliff:g> руу шилжүүлсэн"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"мобайл дата"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"сүлжээний тодорхойгүй төрөл"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-д холбогдож чадсангүй"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" Интернет холболт муу байна."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" Интернет холболт муу байна."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Холболтыг зөвшөөрөх үү?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Програм %1$s нь Wifi сүлжээ %2$s-тай холбох хүсэлтэй байна"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Аппликейшн"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2 дахь ажил <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3 дахь ажил <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Энэ дэлгэцийг тогтоосныг болиулахын тулд Буцах, Тойм гэсэн сонголтыг товшоод, хүлээнэ үү"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Энэ аппыг тогтоосныг болиулах боломжгүй"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Дэлгэцийг тогтоосон"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Дэлгэцийг сулласан"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Тогтоосныг суллахаас өмнө PIN асуух"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Таны админ суулгасан"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Таны админ шинэчилсэн"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Таны админ устгасан"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Батарей хадгалах функц нь таны төхөөрөмжийн цэнэгийг хадгалахын тулд гүйцэтгэлийг багасгаж, чичрэлтийг бууруулж, байршлын үйлчилгээнүүд болон бусад өгөгдлийн хэмжээг багасгадаг. И-мэйл, мессеж болон бусад синхрон хийдэг апликейшнүүд дараа дахин нээгдэх хүртлээ автоматаар шинэчлэлт хийхгүй.\n\nМөн батарей хадгалах функц нь таныг төхөөрөмжөө цэнэглэх үед автоматаар унтарна."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Тэжээл хэмнэгч нь батерейны амийг сайжруулахад туслахын тулд таны төхөөрөмжийн гүйцэтгэлийг багасгаж, чичрэлт, байршлын үйлчилгээнүүд болон ихэнх арын датаг хязгаарладаг. Та и-мэйл, мессеж болон бусад синк хийдэг аппыг нээх хүртэл тэдгээрийг шинэчлэхгүй.\n\nТэжээл хэмнэгч нь таныг төхөөрөмжөө цэнэглэх үед автоматаар унтарна."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Дата ашиглалтыг багасгахын тулд дата хэмнэгч нь зарим апп-г өгөгдлийг дэвсгэрт илгээх болон авахаас сэргийлдэг. Таны одоогийн ашиглаж буй апп нь өгөгдөлд хандах боломжтой хэдий ч цөөн үйлдэл хийнэ. Жишээлбэл зураг харахын тулд та товших шаардлагатай болно."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Өгөгдөл хамгаалагчийг асаах уу?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Асаах"</string>
@@ -1780,14 +1782,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Онцгой байдлын зурвасын тест"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Хариу бичих"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM-г дуу хоолойд зөвшөөрдөггүй"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM-г дуу хоолойд идэвхжүүлдэггүй"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM-г дуу хоолойд зөвшөөрдөггүй"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Утсыг дуу хоолойд зөвшөөрдөггүй"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"гэнэт гарч ирэх цонх"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Энэ товчлолд саяхны апп шаардлагатай"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 83d0765..bd00d46 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -79,8 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"व्हॉइस/आणीबाणी सेवा नाही"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"तुम्ही असलेल्या स्थानी मोबाइल नेटवर्क तात्पुरते उपलब्ध नाही"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"नेटवर्कवर पोहोचूू शकत नाही"</string>
- <!-- no translation found for NetworkPreferenceSwitchSummary (7056776609127756440) -->
- <skip />
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"रीसेप्शन सुधारण्यासाठी, सेटिंग्ज > नेटवर्क आणि इंटरनेट > मोबाइल नेटवर्क > प्राधान्यीकृत नेटवर्क प्रकार बदलून पाहा."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"वाय-फाय कॉलिंग चालू आहे"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"आपात्कालीन कॉलसाठी मोबाइल नेटवर्क असणे आवश्यक आहे."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"अलर्ट"</string>
@@ -1052,12 +1051,10 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"सिस्टम सेटिंग्ज > Apps > डाउनलोड केलेले मध्ये हे पुन्हा-सक्षम करा."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> वर्तमान डिस्प्ले आकार सेटिंगला समर्थन देत नाही आणि अनपेक्षित वर्तन करू शकते."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"नेहमी दर्शवा"</string>
- <!-- no translation found for unsupported_compile_sdk_message (5030433583092006591) -->
+ <!-- no translation found for unsupported_compile_sdk_message (4253168368781441759) -->
<skip />
- <!-- no translation found for unsupported_compile_sdk_show (2681877855260970231) -->
- <skip />
- <!-- no translation found for unsupported_compile_sdk_check_update (3312723623323216101) -->
- <skip />
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"नेहमी दर्शवा"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"अपडेट आहे का ते तपासा"</string>
<string name="smv_application" msgid="3307209192155442829">"अॅप <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ने तिच्या स्वयं-लागू केलेल्या StrictMode धोरणाचे उल्लंघन केले आहे."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> प्रक्रियेने तिच्या स्वतः-लागू केलेल्या StrictMode धोरणाचे उल्लंघन केले."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android श्रेणीसुधारित होत आहे..."</string>
@@ -1123,12 +1120,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"नेटवर्कवर साइन इन करा"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <!-- no translation found for wifi_no_internet (8938267198124654938) -->
- <skip />
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi ला इंटरनेटचा अॅक्सेस नाही"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"पर्यायांसाठी टॅप करा"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> वर स्विच केले"</string>
- <!-- no translation found for network_switch_metered_detail (775163331794506615) -->
- <skip />
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> कडे इंटरनेटचा अॅक्सेस नसताना डिव्हाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> वापरते. शुल्क लागू शकते."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> वरून <xliff:g id="NEW_NETWORK">%2$s</xliff:g> वर स्विच केले"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"मोबाइल डेटा"</item>
@@ -1644,7 +1639,8 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"आपल्या प्रशासकाने इंस्टॉल केले"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"आपल्या प्रशासकाने अपडेट केले"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"आपल्या प्रशासकाने हटवले"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"बॅटरी लाइफ सुधारित करण्यासाठी, बॅटरी सेव्हर तुमच्या डिव्हाइस ची कामगिरी कमी करतो आणि कंपन, स्थान सेवा आणि बराच पार्श्वभूमी डेटा मर्यादित करतो. सिंकवर अवलंबून असणारे ईमेल, मेसेजिंग आणि इतर अॅप्स तुम्ही उघडल्याशिवाय अपडेट होऊ शकत नाहीत.\n\nतुमचे डिव्हाइस चार्ज होत असते तेव्हा बॅटरी सेव्हर आपोआप बंद होतो."</string>
+ <!-- no translation found for battery_saver_description (5394663545060026162) -->
+ <skip />
<string name="data_saver_description" msgid="6015391409098303235">"डेटा वापर कमी करण्यात मदत करण्यासाठी, डेटा सर्व्हर काही अॅप्सना पार्श्वभूमीमध्ये डेटा पाठविण्यास किंवा प्राप्त करण्यास प्रतिबंधित करतो. आपण सध्या वापरत असलेला अॅप डेटामध्ये प्रवेश करू शकतो परंतु तसे तो खूप कमी वेळा करू शकतो. याचा अर्थ, उदाहरणार्थ, आपण इमेज टॅप करेपर्यंत त्या प्रदर्शित करणार नाहीत असा असू शकतो."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"डेटा बचतकर्ता चालू करायचा?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"चालू करा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 3753fb2..26837b3 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Tiada perkhidmatan suara/kecemasan"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Tidak ditawarkan oleh rangkaian mudah alih di lokasi anda untuk sementara waktu"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Tidak dapat mencapai rangkaian"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Untuk memperbaik penerimaan, cuba tukar jenis rangkaian yang dipilih di Tetapan > Rangkaian & Internet > Rangkaian mudah alih > Jenis rangkaian pilihan."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Untuk memperbaik penerimaan, cuba tukar jenis rangkaian yang dipilih di Tetapan > Rangkaian & Internet > Rangkaian mudah alih > Jenis rangkaian pilihan."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Panggilan Wi-Fi aktif"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Rangkaian mudah alih diperlukan untuk membuat panggilan kecemasan."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Makluman"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Dayakan semula kod kompak ini tetapan Sistem > Apl > Dimuat turun."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak menyokong tetapan saiz Paparan semasa dan mungkin menunjukkan gelagat yang tidak dijangka."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Sentiasa tunjukkan"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> telah dibina untuk versi yang tidak serasi dengan OS Android dan mungkin menunjukkan gelagat yang tidak dijangka. Versi kemas kini apl mungkin tersedia."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Sentiasa tunjukkan"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Semak kemas kini"</string>
<string name="smv_application" msgid="3307209192155442829">"Apl <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) telah melanggar dasar Mod Tegasnya sendiri."</string>
<string name="smv_process" msgid="5120397012047462446">"Proses <xliff:g id="PROCESS">%1$s</xliff:g> telah melanggar dasar Mod Tegasnya sendiri."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android sedang menaik taraf..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Log masuk ke rangkaian"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi tiada akses Internet"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi tiada akses Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Ketik untuk mendapatkan pilihan"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Beralih kepada <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Peranti menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> apabila <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tiada akses Internet. Bayaran mungkin dikenakan."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Peranti menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> apabila <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tiada akses Internet. Bayaran mungkin dikenakan."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Beralih daripada <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kepada <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"data mudah alih"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"jenis rangkaian tidak diketahui"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Tidak boleh menyambung kepada Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" mempunyai sambungan internet yang kurang baik."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" mempunyai sambungan internet yang kurang baik."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Benarkan sambungan?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikasi %1$s ingin menyambung ke Rangkaian Wifi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Satu aplikasi"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> kerja ke-2"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> kerja ke-3"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Untuk menyahsematkan skrin ini, sentuh & tahan butang Kembali dan Ikhtisar"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Apl ini tidak dapat dinyahsematkan"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Skrin disemat"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Skrin dinyahsemat"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Minta PIN sebelum menyahsemat"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Dipasang oleh pentadbir anda"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Dikemas kini oleh pentadbir anda"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Dipadamkan oleh pentadbir anda"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Untuk membantu memperbaik hayat bateri, penjimat bateri mengurangkan prestasi peranti anda dan mengehadkan getaran, perkhidmatan lokasi dan kebanyakan data latar belakang. E-mel, pemesejan dan apl lain yang bergantung kepada penyegerakan mungkin tidak mengemas kini, melainkan anda membuka apl itu.\n\nPenjimat bateri dimatikan secara automatik semasa peranti anda sedang dicas."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Untuk mempertingkatkan hayat bateri, Penjimat Bateri mengurangkan prestasi peranti anda dan mengehadkan getaran, perkhidmatan lokasi dan kebanyakan data latar belakang. E-mel, pemesejan dan apl lain yang bergantung pada penyegerakan mungkin tidak dikemas kini, melainkan anda membuka apl itu.\n\nPenjimat Bateri dimatikan secara automatik apabila peranti anda sedang dicas."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Untuk membantu mengurangkan penggunaan data, Penjimat Data menghalang sesetengah apl daripada menghantar atau menerima data di latar. Apl yang sedang digunakan boleh mengakses data tetapi mungkin tidak secara kerap. Perkara ini mungkin bermaksud bahawa imej tidak dipaparkan sehingga anda mengetik pada imej itu, contohnya."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Hidupkan Penjimat Data?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Hidupkan"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Ujian mesej kecemasan"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Balas"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM tidak dibenarkan untuk suara"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM tidak diperuntukkan untuk suara"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM tidak dibenarkan untuk suara"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefon tidak dibenarkan untuk suara"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Tetingkap Timbul"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Pintasan ini memerlukan apl yang terbaharu"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 0f0ae23..0a2118e 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"ဖုန်း/အရေးပေါ် ဝန်ဆောင်မှုများမရရှိနိုင်ပါ"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"သင်၏ ဒေသတွင် မိုဘိုင်းကွန်ရက် ယာယီမရရှိနိုင်ပါ"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"ကွန်ရက်ကို ချိတ်ဆက်၍မရပါ"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"လိုင်းဖမ်းယူမှု ကောင်းမွန်စေရန် ဆက်တင်များ > ကွန်ရက်နှင့် အင်တာနက် > မိုဘိုင်းကွန်ရက်များ > အသုံးပြုလိုသည့် ကွန်ရက်အမျိုးအစားတွင် ရွေးချယ်ထားသည့် အမျိုးအစားကို ပြောင်းကြည့်ပါ။"</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"လိုင်းဖမ်းယူမှု ကောင်းမွန်စေရန် ဆက်တင်များ > ကွန်ရက်နှင့် အင်တာနက် > မိုဘိုင်းကွန်ရက်များ > အသုံးပြုလိုသည့် ကွန်ရက်အမျိုးအစားတွင် ရွေးချယ်ထားသည့် အမျိုးအစားကို ပြောင်းကြည့်ပါ။"</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi ခေါ်ဆိုမှုကို အသုံးပြုနေပါသည်"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"အရေးပေါ်ဖုန်းခေါ်ဆိုရန် မိုဘိုင်းကွန်ရက်ကို လိုအပ်သည်။"</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"သတိပေးချက်များ"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ဒါကို စနစ် ဆက်တင်များထဲ ပြန်ဖွင့်ပေးရန် > Apps > ဒေါင်းလုဒ် လုပ်ပြီး။"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် လက်ရှိ မျက်နှာပြင်အရွယ်အစားကို ပံ့ပိုးထားခြင်း မရှိပါ။ မမျှော်လင့်နိုင်သည့် ချွတ်ယွင်းချက်များ ဖြစ်ပေါ်နိုင်ပါသည်။"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"အမြဲပြပါ"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"ကိုက်ညီမှုမရှိသည့် Android OS ဗားရှင်းအတွက် <xliff:g id="APP_NAME">%1$s</xliff:g> ကို ပြုလုပ်ထားခြင်းဖြစ်ပြီး ပုံမှန်အလုပ်မလုပ်နိုင်ပါ။ ဤအက်ပ်အတွက် အပ်ဒိတ်လုပ်ထားသည့် ဗားရှင်း ရနိုင်ပါမည်။"</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"အမြဲပြရန်"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"အပ်ဒိတ်အတွက် စစ်ကြည့်ရန်"</string>
<string name="smv_application" msgid="3307209192155442829">"app <xliff:g id="APPLICATION">%1$s</xliff:g> (လုပ်ငန်းစဉ် <xliff:g id="PROCESS">%2$s</xliff:g>) က ကိုယ်တိုင် ပြဌာန်းခဲ့သည့် StrictMode မူဝါဒကို ချိုးဖောက်ခဲ့သည်။"</string>
<string name="smv_process" msgid="5120397012047462446">"ဤ<xliff:g id="PROCESS">%1$s</xliff:g>ဖြစ်စဥ်မှာ ကိုယ်တိုင်အကျိုးသက်ရောက်သော StrictModeမူဝါဒအား ချိုးဖောက်သည်"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"အန်ဒရွိုက်ကို မွမ်းမံနေ…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"ကွန်ယက်သို့ လက်မှတ်ထိုးဝင်ရန်"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"ဝိုင်-ဖို်ငတွင် အင်တာနက် ဝင်ရောက်သုံးခွင့် မရှိပါ"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi တွင် အင်တာနက်ချိတ်ဆက်မှု မရှိပါ"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"အခြားရွေးချယ်စရာများကိုကြည့်ရန် တို့ပါ"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"စက်ပစ္စည်းသည် <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ဖြင့် အင်တာနက် အသုံးမပြုနိုင်သည့်အချိန်တွင် <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ကို သုံးပါသည်။ ဒေတာသုံးစွဲခ ကျသင့်နိုင်ပါသည်။"</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ဖြင့် အင်တာနက် အသုံးမပြုနိုင်သည့်အချိန်တွင် စက်ပစ္စည်းသည် <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ကို သုံးပါသည်။ ဒေတာသုံးစွဲခ ကျသင့်နိုင်ပါသည်။"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> မှ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"မိုဘိုင်းဒေတာ"</item>
@@ -1130,7 +1133,8 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"အမည်မသိကွန်ရက်အမျိုးအစား"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ဝိုင်ဖိုင်ကိုချိတ်ဆက်မရပါ"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" အင်တာနက် ဆက်သွယ်မှု ကောင်းကောင်းမရှိပါ"</string>
+ <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+ <skip />
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"ချိတ်ဆက်မှုကို ခွင့်ပြုမလား?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"အပလီကေးရှင်း %1$s သည် ဝိုင်ဖိုင်ကွန်ရက် %2$s ကိုချိတ်ဆက်လိုသည်"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"အပလီကေးရှင်း"</string>
@@ -1626,7 +1630,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"ဒုတိယအလုပ် <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"တတိယအလုပ် <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"ဤမျက်နှာပြင်ကို ပင်ဖြုတ်ရန်အတွက် \'နောက်သို့\' နှင့် \'အနှစ်ချုပ်\' ခလုတ်များကို အတူတို့၍ ထိထားပါ"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"ဤအက်ပ်ကို ပင်ဖြုတ်၍မရပါ"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"မျက်နှာပြင်ကို ပင်ထိုးထား"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"မျက်နှာပြင် ပင်ထိုးမှု ဖြတ်လိုက်ပြီ"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ပင်မဖြုတ်မီမှာ PIN ကို မေးကြည့်ရန်"</string>
@@ -1635,7 +1638,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"သင်၏ စီမံခန့်ခွဲသူက ထည့်သွင်းထားသည်"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"သင်၏ စီမံခန့်ခွဲသူက အပ်ဒိတ်လုပ်ထားသည်"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"သင်၏ စီမံခန့်ခွဲသူက ဖျက်လိုက်ပါပြီ"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"ဘက်ထရီသက်တမ်း ကြာရှည်ခံရန် ဘက်ထရီအားထိန်းသည် သင့်ကိရိယာ၏ ဆောင်ရွက်ချက်ကိုလျှော့ပေးပြီး တုန်ခါမှု၊ တည်နေရာဝန်ဆောင်မှုများနှင့် နောက်ခံဒေတာအများစုကို ကန့်သတ်ပေး၏။ စင့်ခ်လုပ်ပေးရလေ့ရှိသည့် အီးမေးလ်၊ စာပို့ခြင်းနှင့် အခြားအပလီကေးရှင်းများကို ၎င်းတို့အား သင် ဖွင့်မှသာ အပ်ဒိတ်လုပ်မည်ဖြစ်၏။ \n\n ကိရိယာအား အားသွင်းနေစဉ် ဘက်ထရီအားထိန်းကို အလိုအလျောက် ပိတ်ထားသည်။"</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"ဘက်ထရီ သက်တမ်းကြာရှည်ခံရန်အတွက် ဘက်ထရီ အားထိန်းသည် သင့်စက်ပစ္စည်း၏ စွမ်းဆောင်ရည်၊ တုန်ခါမှု၊ တည်နေရာ ဝန်ဆောင်မှုများနှင့် နောက်ခံဒေတာ အများစုတို့ကို လျှော့ချပေးပါသည်။ စင့်ခ်လုပ်ခြင်းကို အားထားနေရသည့် အီးမေးလ်၊ စာပို့ခြင်းနှင့် အခြားအက်ပ်များကို သင်မဖွင့်မချင်း အပ်ဒိတ်လုပ်မည် မဟုတ်ပါ။\n\nသင့်စက်ပစ္စည်းကို အားသွင်းနေသည့်အခါ ဘက်ထရီ အားထိန်းကို အလိုအလျောက် ပိတ်လိုက်ပါမည်။"</string>
<string name="data_saver_description" msgid="6015391409098303235">"ဒေတာအသုံးလျှော့ချနိုင်ရန် အက်ပ်များကို နောက်ခံတွင် ဒေတာပို့ခြင်းနှင့် လက်ခံခြင်းမရှိစေရန် ဒေတာချွေတာမှုစနစ်က တားဆီးထားပါသည်။ ယခုအက်ပ်ဖြင့် ဒေတာအသုံးပြုနိုင်သော်လည်း အကြိမ်လျှော့၍သုံးရပါမည်။ ဥပမာ၊ သင် မတို့မချင်း ပုံများပေါ်လာမည် မဟုတ်ပါ။"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ဒေတာအသုံးပြုမှု ချွေတာမှုစနစ်ကို ဖွင့်မလား။"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ဖွင့်ပါ"</string>
@@ -1782,14 +1785,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"အရေးပေါ် မက်ဆေ့ဂျ် စမ်းသပ်မှု"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"စာပြန်ရန်"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"စကားသံအတွက် ဆင်းမ်ကို ခွင့်မပြုပါ"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"စကားသံအတွက် ဆင်းမ်ကို ထောက်ပံ့မထားပါ"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"စကားသံအတွက် ဆင်းမ်ကို ခွင့်မပြုပါ"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"စကားသံအတွက် ဖုန်းကို ခွင့်မပြုပါ"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"ပေါ့ပ်အပ် ဝင်းဒိုး"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"ဤဖြတ်လမ်းလင့်ခ်ကို အသုံးပြုနိုင်ရန် နောက်ဆုံးထွက်အက်ပ် လိုအပ်ပါသည်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 93e978c..98535c5 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Ingen tale-/nødtjeneste"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Tilbys midlertidig ikke gjennom mobilnettverket der du er"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Får ikke kontakt med nettverket"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"For å forbedre signalet, prøv å endre valgt nettverkstype i Innstillinger > Nettverk og Internett > Mobilnettverk > Foretrukket nettverkstype."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"For å forbedre signalet, prøv å endre valgt nettverkstype i Innstillinger > Nettverk og Internett > Mobilnettverk > Foretrukket nettverkstype."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi-anrop er aktivt"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Du trenger et mobilnettverk for å utføre nødanrop."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Varsler"</string>
@@ -204,7 +204,7 @@
<string name="reboot_safemode_title" msgid="7054509914500140361">"Start på nytt i sikker modus"</string>
<string name="reboot_safemode_confirm" msgid="55293944502784668">"Ønsker du å starte på nytt i sikker modus? Dette deaktiverer alle tredjepartsprogrammene du har installert. De gjenopprettes når du starter på nytt."</string>
<string name="recent_tasks_title" msgid="3691764623638127888">"Nylig"</string>
- <string name="no_recent_tasks" msgid="8794906658732193473">"Ingen nylige apper."</string>
+ <string name="no_recent_tasks" msgid="8794906658732193473">"Ingen nylig brukte apper."</string>
<string name="global_actions" product="tablet" msgid="408477140088053665">"Innstillinger for nettbrett"</string>
<string name="global_actions" product="tv" msgid="7240386462508182976">"Alternativer for TV"</string>
<string name="global_actions" product="default" msgid="2406416831541615258">"Telefoninnstillinger"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reaktiver dette i systeminnstillingene > Apper > Nedlastet."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> støtter ikke den nåværende innstillingen for skjermstørrelse og fungerer kanskje ikke som den skal."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Vis alltid"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> ble utviklet for en inkompatibel versjon av Android OS og fungerer kanskje ikke som forventet. En oppdatert versjon av appen kan være tilgjengelig."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Vis alltid"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Se etter oppdateringer"</string>
<string name="smv_application" msgid="3307209192155442829">"Appen <xliff:g id="APPLICATION">%1$s</xliff:g> (prosessen <xliff:g id="PROCESS">%2$s</xliff:g>) har brutt de selvpålagte StrictMode-retningslinjene."</string>
<string name="smv_process" msgid="5120397012047462446">"Prosessen<xliff:g id="PROCESS">%1$s</xliff:g> har brutt de selvpålagte StrictMode-retningslinjene."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android oppgraderes …"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Logg på nettverk"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi har ikke Internett-tilgang"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi har ikke Internett-tilgang"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Trykk for å få alternativer"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Byttet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Enheten bruker <xliff:g id="NEW_NETWORK">%1$s</xliff:g> når <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ikke har Internett-tilgang. Avgifter kan påløpe."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Enheten bruker <xliff:g id="NEW_NETWORK">%1$s</xliff:g> når <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ikke har Internett-tilgang. Avgifter kan påløpe."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Byttet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobildata"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"en ukjent nettverkstype"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan ikke koble til Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dårlig Internett-tilkobling."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" har en dårlig Internett-tilkobling."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vil du tillat tilkoblingen?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Appen %1$s vil koble til Wi-Fi-nettverket %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"En app"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Andre <xliff:g id="LABEL">%1$s</xliff:g> for jobben"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Tredje <xliff:g id="LABEL">%1$s</xliff:g> for jobben"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"For å løsne denne skjermen, trykk på og hold inne Tilbake- og Oversikt-knappene"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Denne appen kan ikke løsnes"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Skjermen er festet"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Skjermen er løsnet"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"PIN-kode for å løsne apper"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Installert av administratoren din"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Oppdatert av administratoren din"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Slettet av administratoren din"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Med batterisparing forlenges batteritiden ved at bruk av for eksempel vibrasjon, posisjonstjenester og bakgrunnsdata reduseres. E-post, sending av meldinger og andre apper som er avhengig av synkronisering, oppdateres kanskje ikke med mindre du åpner dem.\n\nBatterisparing slås av automatisk når enheten lader."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Med batterisparing forlenges batterilevetiden ved at bruk av for eksempel vibrasjon, posisjonstjenester og bakgrunnsdata reduseres. E-post, sending av meldinger og andre apper som er avhengig av synkronisering, oppdateres kanskje ikke med mindre du åpner dem.\n\nBatterisparing slås av automatisk når enheten lader."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Datasparing hindrer at apper kan sende og motta data i bakgrunnen. Apper du bruker i øyeblikket, bruker ikke data i like stor grad – for eksempel vises ikke bilder før du trykker på dem."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Vil du slå på Datasparing?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Slå på"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test av nødmeldinger"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Svar"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM-kortet har ikke tillatelse til tale"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM-kortet er ikke klargjort for tale"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM-kortet har ikke tillatelse til tale"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefonen har ikke tillatelse til tale"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Forgrunnsvindu"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Denne snarveien krever den nyeste appen"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index c41547b..f9016de 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"कुनै पनि भ्वाइस/आपतकालीन सेवा उपलब्ध छैन"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"तपाईंको स्थानमा सञ्चालन भइरहेको मोबाइल नेटवर्कले अस्थायी रूपमा यो सुविधा प्रदान गर्दैन"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"नेटवर्कमाथि पहुँच राख्न सकिँदैन"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"रिसेप्सनमा सुधार गर्न प्रणालीहरू > नेटवर्क तथा इन्टरनेट > मोबाइल नेटवर्कहरू > रुचाइएको नेटवर्कको प्रकारमा गई चयन गरिएको प्रकार परिवर्तन गरी हेर्नुहोस्।"</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"रिसेप्सनमा सुधार गर्न सेटिङहरू > नेटवर्क तथा इन्टरनेट > मोबाइल नेटवर्कहरू > रुचाइएको नेटवर्कको प्रकारमा गई चयन गरिएको प्रकार परिवर्तन गरी हेर्नुहोस्।"</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi कलिङ सक्रिय छ"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"आपतकालीन कलहरू गर्न मोबाइल नेटवर्क अनिवार्य छ।"</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"अलर्टहरू"</string>
@@ -1057,6 +1057,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"प्रणाली सेटिङहरूमा यसलाई पुनःसक्षम गराउनुहोस् > अनुप्रयोगहरू > डाउनलोड गरेको।"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले हालको प्रदर्शनको आकार सम्बन्धी सेटिङलाई समर्थन गर्दैन र अप्रत्याशित तरिकाले व्यवहार गर्न सक्छ।"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"सधैँ देखाउनुहोस्"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई Android OS को कुनै नमिल्दो संस्करणका लागि निर्माण गरिएको थियो र यसले अप्रत्याशित ढंगले कार्य गर्नसक्छ। उक्त अनुप्रयोगको कुनै अद्यावधिक संस्करण उपलब्ध हुनसक्छ।"</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"जुनसुकै बेला देखाउनुहोस्"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"अद्यावधिकका लागि जाँच गर्नुहोस्"</string>
<string name="smv_application" msgid="3307209192155442829">"अनुप्रयोग <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ले यसको स्वयं-लागु गरिएको स्ट्रिटमोड नीति उलङ्घन गरेको छ।"</string>
<string name="smv_process" msgid="5120397012047462446">"प्रक्रिया <xliff:g id="PROCESS">%1$s</xliff:g> यसको आफ्नै कडामोड नीतिका कारण उल्लङ्घन गरिएको छ।"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"एन्ड्रोइड अपग्रेड हुँदैछ…"</string>
@@ -1122,10 +1125,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"सञ्जालमा साइन इन गर्नुहोस्"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi मा इन्टरनेट पहुँच छैन"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi मार्फत इन्टरनेटमाथि पहुँच राख्न सकिँदैन"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"विकल्पहरूका लागि ट्याप गर्नुहोस्"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> मा बदल्नुहोस्"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> मा इन्टरनेट माथिको पहुँच नहुँदा यन्त्रले <xliff:g id="NEW_NETWORK">%1$s</xliff:g> को प्रयोग गर्दछ। शुल्कहरू लागू हुन सक्छन्।"</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> मार्फत इन्टरनेटमाथि पहुँच राख्न नसकेको अवस्थामा यन्त्रले <xliff:g id="NEW_NETWORK">%1$s</xliff:g> प्रयोग गर्दछ। शुल्क लाग्न सक्छ।"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> बाट <xliff:g id="NEW_NETWORK">%2$s</xliff:g> मा परिवर्तन गरियो"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"मोबाइल डेटा"</item>
@@ -1136,7 +1139,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"नेटवर्कको कुनै अज्ञात प्रकार"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाइ-फाइसँग जडान गर्न सकेन"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" कमजोर इन्टरनेट जडान छ।"</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" खराब इन्टरनेट जडान रहेको छ।"</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"जडान अनुमति दिने हो?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"अनुप्रयोग %1$s Wifi सञ्जाल %2$s मा जडान गर्न चाहन्छ"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"एउटा अनुप्रयोग"</string>
@@ -1640,7 +1643,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"तपाईंका प्रशासकले स्थापना गर्नुभएको"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"तपाईंका प्रशासकले अद्यावधिक गर्नुभएको"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"तपाईंका प्रशासकले मेट्नुभएको"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"ब्याट्रीको आयु सुधार्न, ब्याट्री संरक्षकले तपाईंको यन्त्रको कार्यसम्पादन घटाउँछ र भाइब्रेसन, स्थान सेवा र बहुसंख्यक पृष्ठभूमि डेटा सीमित गर्दछ। इमेल, सन्देश, र अन्य अनुप्रयोगहरू जुन सिङ्कमा भर पर्छन् अद्यावधिक नहुन सक्छन् जबसम्म तपाईं तिनीहरूलाई खोल्नुहुन्न\n\n ब्याट्री संरक्षक स्वत: निस्कृय हुन्छ जब तपाईंको यन्त्र चार्ज हुँदै हुन्छ।"</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"ब्याट्रीको आयु सुधार्ने कार्यमा मद्दत गर्न ब्याट्री सेभरले तपाईंको यन्त्रको कार्यसम्पादन घटाउँछ र कम्पन, स्थानसम्बन्धी सेवा तथा पृष्ठभूमिको प्रायः जसो डेटा सीमित गर्दछ। तपाईंले सिंकमा भरपर्ने इमेल, सन्देश र अन्य अनुप्रयोगहरू नखोलेसम्म ती अद्यावधिक नहुन पनि सक्छन्\n\n तपाईंको यन्त्र चार्ज भइरहेको अवस्थामा ब्याट्री सेभर स्वत: निष्क्रिय हुन्छ।"</string>
<string name="data_saver_description" msgid="6015391409098303235">"डेटाको प्रयोगलाई कम गर्नमा मद्दतका लागि डेटा सर्भरले केही अनुप्रयोगहरूलाई पृष्ठभूमिमा डेटा पठाउन वा प्राप्त गर्नबाट रोक्दछ। तपाईँले हाल प्रयोग गरिरहनुभएको अनु्प्रयोगले डेटामाथि पहुँच राख्न सक्छ, तर त्यसले यो काम थोरै पटक गर्न सक्छ। उदाहरणका लागि यसको मतलब यो हुन सक्छ: तपाईँले छविहरूलाई ट्याप नगरेसम्म ती प्रदर्शन हुँदैनन्।"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"डेटा सेभरलाई सक्रिय गर्ने हो?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"सक्रिय गर्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index f99d531..b06728a 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Geen service voor spraak-/noodoproepen"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Tijdelijk niet aangeboden door het mobiele netwerk op je locatie"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Kan netwerk niet bereiken"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Als je de ontvangst wilt verbeteren, kun je het netwerktype wijzigen dat is geselecteerd bij Instellingen > Netwerk en internet > Mobiele netwerken > Voorkeursnetwerktype."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Als je de ontvangst wilt verbeteren, kun je het netwerktype wijzigen dat is geselecteerd bij Instellingen > Netwerk en internet > Mobiele netwerken > Voorkeursnetwerktype."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Bellen via wifi is actief"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Voor noodoproepen is een mobiel netwerk vereist."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Meldingen"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"U kunt dit opnieuw inschakelen via Systeeminstellingen > Apps > Gedownload."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> biedt geen ondersteuning voor de huidige instelling voor weergavegrootte en kan onverwacht gedrag vertonen."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Altijd weergeven"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> is gemaakt voor een niet-geschikte versie van het Android-besturingssysteem en kan onverwacht gedrag vertonen. Mogelijk is er een geüpdatete versie van de app beschikbaar."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Altijd weergeven"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Controleren op update"</string>
<string name="smv_application" msgid="3307209192155442829">"De app <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) heeft het zelf afgedwongen StrictMode-beleid geschonden."</string>
<string name="smv_process" msgid="5120397012047462446">"Het proces <xliff:g id="PROCESS">%1$s</xliff:g> heeft het zelf afgedwongen StrictMode-beleid geschonden."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android wordt bijgewerkt..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Inloggen bij netwerk"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wifi-netwerk heeft geen internettoegang"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wifi-netwerk heeft geen internettoegang"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tik voor opties"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Overgeschakeld naar <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Apparaat gebruikt <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internetverbinding heeft. Er kunnen kosten in rekening worden gebracht."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Apparaat gebruikt <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internetverbinding heeft. Er kunnen kosten in rekening worden gebracht."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Overgeschakeld van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> naar <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobiele data"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"een onbekend netwerktype"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan geen verbinding maken met wifi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" heeft een slechte internetverbinding."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" heeft een slechte internetverbinding."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Verbinding toestaan?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"App %1$s wil verbinding maken met wifi-netwerk %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Een app"</string>
@@ -1634,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Geïnstalleerd door je beheerder"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Geüpdatet door je beheerder"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Verwijderd door je beheerder"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Batterijbesparing beperkt de prestaties van je apparaat, de trilstand, locatieservices en de meeste achtergrondgegevens om de gebruiksduur van de batterij te verlengen.\n\nBatterijbesparing wordt automatisch uitgeschakeld terwijl je apparaat wordt opgeladen."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Batterijbesparing beperkt de prestaties van je apparaat, de trilstand, locatieservices en de meeste achtergrondgegevens om de gebruiksduur van de batterij te verlengen.\n\nBatterijbesparing wordt automatisch uitgeschakeld terwijl je apparaat wordt opgeladen."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Databesparing beperkt het datagebruik door te voorkomen dat sommige apps gegevens verzenden of ontvangen op de achtergrond. De apps die je open hebt, kunnen nog steeds data verbruiken, maar doen dit minder vaak. Afbeeldingen worden dan bijvoorbeeld niet weergegeven totdat je erop tikt."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Databesparing inschakelen?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Inschakelen"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index d269fac..b5811ac 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"ਕੋਈ ਆਵਾਜ਼ੀ/ਸੰਕਟਕਾਲੀਨ ਸੇਵਾ ਨਹੀਂ"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"ਤੁਹਾਡੇ ਟਿਕਾਣੇ \'ਤੇ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਵੱਲੋਂ ਉਪਲਬਧ ਨਹੀਂ ਕਰਵਾਈ ਗਈ"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"ਨੈੱਟਵਰਕ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"ਸਿਗਨਲ ਪ੍ਰਾਪਤੀ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ, ਸੈਟਿੰਗਾਂ > ਨੈੱਟਵਰਕ ਅਤੇ ਇੰਟਰਨੈੱਟ > ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ > ਤਰਜੀਹੀ ਨੈੱਟਵਰਕ ਦੀ ਕਿਸਮ \'ਤੇ ਜਾਓ ਅਤੇ ਚੁਣੀ ਗਈ ਕਿਸਮ ਨੂੰ ਬਦਲਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"ਸਿਗਨਲ ਪ੍ਰਾਪਤੀ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ, ਸੈਟਿੰਗਾਂ > ਨੈੱਟਵਰਕ ਅਤੇ ਇੰਟਰਨੈੱਟ > ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ > ਤਰਜੀਹੀ ਨੈੱਟਵਰਕ ਦੀ ਕਿਸਮ \'ਤੇ ਜਾਓ ਅਤੇ ਚੁਣੀ ਗਈ ਕਿਸਮ ਨੂੰ ਬਦਲਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ ਕਿਰਿਆਸ਼ੀਲ ਹੈ"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"ਸੰਕਟਕਾਲੀਨ ਕਾਲਾਂ ਲਈ ਕਿਸੇ ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ।"</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"ਸੁਚੇਤਨਾਵਾਂ"</string>
@@ -1051,6 +1051,10 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ਸਿਸਟਮ ਸੈਟਿੰਗਾਂ > ਐਪਾਂ > ਡਾਊਨਲੋਡ ਕੀਤਿਆਂ ਵਿੱਚ ਇਸਨੂੰ ਮੁੜ-ਸਮਰੱਥ ਬਣਾਓ।"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਵਰਤਮਾਨ ਡਿਸਪਲੇ ਆਕਾਰ ਸੈਟਿੰਗ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ ਹੈ ਅਤੇ ਅਣਕਿਆਸੇ ਤੌਰ \'ਤੇ ਵਿਹਾਰ ਕਰ ਸਕਦੀ ਹੈ।"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ਹਮੇਸ਼ਾ ਦਿਖਾਓ"</string>
+ <!-- no translation found for unsupported_compile_sdk_message (4253168368781441759) -->
+ <skip />
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"ਹਮੇਸਾਂ ਦਿਖਾਓ"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"ਅੱਪਡੇਟ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
<string name="smv_application" msgid="3307209192155442829">"ਐਪ <xliff:g id="APPLICATION">%1$s</xliff:g> (ਪ੍ਰਕਿਰਿਆ <xliff:g id="PROCESS">%2$s</xliff:g>) ਨੇ ਆਪਣੀ ਖੁਦ-ਲਾਗੂ ਕੀਤੀ ਸਟ੍ਰਿਕਟਮੋਡ ਨੀਤੀ ਦੀ ਉਲੰਘਣਾ ਕੀਤੀ ਹੈ।"</string>
<string name="smv_process" msgid="5120397012047462446">"ਪ੍ਰਕਿਰਿਆ <xliff:g id="PROCESS">%1$s</xliff:g> ਨੇ ਆਪਣੀ ਖੁਦ-ਲਾਗੂ ਕੀਤੀ ਸਟ੍ਰਿਕਟਮੋਡ ਨੀਤੀ ਦੀ ਉਲੰਘਣਾ ਕੀਤੀ ਹੈ।"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android ਅਪਗ੍ਰੇਡ ਕਰ ਰਿਹਾ ਹੈ…"</string>
@@ -1116,10 +1120,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"ਨੈੱਟਵਰਕ \'ਤੇ ਸਾਈਨ-ਇਨ ਕਰੋ"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"ਵਾਈ-ਫਾਈ ਦੀ ਕੋਈ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"ਵਾਈ-ਫਾਈ ਦੀ ਕੋਈ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ਵਿਕਲਪਾਂ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"ਬਦਲਕੇ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ਲਿਆਂਦਾ ਗਿਆ"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ਦੀ ਇੰਟਰਨੈੱਟ \'ਤੇ ਪਹੁੰਚ ਨਾ ਹੋਣ \'ਤੇ ਡੀਵਾਈਸ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ। ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ।"</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ਦੀ ਇੰਟਰਨੈੱਟ \'ਤੇ ਪਹੁੰਚ ਨਾ ਹੋਣ \'ਤੇ ਡੀਵਾਈਸ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ। ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ।"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ਤੋਂ ਬਦਲਕੇ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> \'ਤੇ ਕੀਤਾ ਗਿਆ"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"ਮੋਬਾਈਲ ਡਾਟਾ"</item>
@@ -1130,7 +1134,8 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ਇੱਕ ਅਗਿਆਤ ਨੈੱਟਵਰਕ ਕਿਸਮ"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ਵਾਈ-ਫਾਈ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਹੋ ਸਕਿਆ"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ਇਸਦਾ ਇੱਕ ਖਰਾਬ ਇੰਟਰਨੈੱਟ ਕਨੈਕਸ਼ਨ ਹੈ।"</string>
+ <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+ <skip />
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"ਕੀ ਕਨੈਕਸ਼ਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"ਐਪਲੀਕੇਸ਼ਨ %1$s ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ %2$s ਨਾਲ ਕਨੈਕਟ ਕਰਨਾ ਚਾਹੁੰਦੀ ਹੈ"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"ਇੱਕ ਐਪਲੀਕੇਸ਼ਨ"</string>
@@ -1634,7 +1639,8 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਸਥਾਪਤ ਕੀਤਾ ਗਿਆ"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਮਿਟਾਇਆ ਗਿਆ"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"ਬੈਟਰੀ ਲਾਈਫ਼ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਵਿੱਚ ਸਹਾਇਤਾ ਕਰਨ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦਾ ਪ੍ਰਦਰਸ਼ਨ ਘਟਾਉਂਦਾ ਹੈ ਅਤੇ ਵਾਈਬ੍ਰੇਸ਼ਨ, ਟਿਕਾਣਾ ਸੇਵਾਵਾਂ ਅਤੇ ਜ਼ਿਆਦਾਤਰ ਬੈਕਗ੍ਰਾਊਂਡ ਡਾਟੇ ਨੂੰ ਸੀਮਿਤ ਕਰਦਾ ਹੈ। ਈਮੇਲ, ਸੁਨੇਹਾ ਭੇਜਣ ਅਤੇ ਹੋਰ ਐਪਾਂ, ਜੋ ਸਮਕਾਲੀਕਰਨ \'ਤੇ ਨਿਰਭਰ ਹਨ, ਉਹ ਉਦੋਂ ਤੱਕ ਅੱਪਡੇਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਉਹਨਾਂ ਨੂੰ ਖੋਲ੍ਹਦੇ ਨਹੀਂ।\n\nਬੈਟਰੀ ਸੇਵਰ ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਬੰਦ ਹੁੰਦਾ ਹੈ ਜਦੋਂ ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੁੰਦਾ ਹੈ।"</string>
+ <!-- no translation found for battery_saver_description (5394663545060026162) -->
+ <skip />
<string name="data_saver_description" msgid="6015391409098303235">"ਡਾਟਾ ਵਰਤੋਂ ਘਟਾਉਣ ਵਿੱਚ ਮਦਦ ਲਈ, ਡਾਟਾ ਸੇਵਰ ਕੁਝ ਐਪਾਂ ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਡਾਟਾ ਭੇਜਣ ਜਾਂ ਪ੍ਰਾਪਤ ਕਰਨ ਤੋਂ ਰੋਕਦਾ ਹੈ। ਤੁਹਾਡੇ ਵੱਲੋਂ ਵਰਤਮਾਨ ਤੌਰ \'ਤੇ ਵਰਤੀ ਜਾ ਰਹੀ ਐਪ ਡਾਟਾ \'ਤੇ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ, ਪਰ ਉਹ ਇੰਝ ਕਦੇ-ਕਦਾਈਂ ਕਰ ਸਕਦੀ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਸ ਦਾ ਮਤਲਬ ਇਹ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਚਿੱਤਰ ਤਦ ਤੱਕ ਨਹੀਂ ਪ੍ਰਦਰਸ਼ਿਤ ਕੀਤੇ ਜਾਂਦੇ, ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਉਹਨਾਂ \'ਤੇ ਟੈਪ ਨਹੀਂ ਕਰਦੇ।"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ਕੀ ਡਾਟਾ ਸੇਵਰ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ਚਾਲੂ ਕਰੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index d7c10ec..9e8fb3c 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -81,7 +81,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Brak usługi połączeń głosowych/alarmowych"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Usługa tymczasowo nieoferowana przez sieć komórkową w Twojej lokalizacji"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Brak zasięgu sieci"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Aby poprawić odbiór, zmień typ sieci: wybierz Ustawienia > Sieć i internet > Sieci komórkowe > Preferowany typ sieci."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Aby poprawić odbiór, zmień typ sieci: wybierz Ustawienia > Sieć i internet > Sieci komórkowe > Preferowany typ sieci."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Funkcja Połączenia przez Wi‑Fi jest aktywna"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Połączenia alarmowe wymagają sieci komórkowej."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Alerty"</string>
@@ -275,7 +275,7 @@
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"dostęp do kalendarza"</string>
<string name="permgrouprequest_calendar" msgid="6704529828699071445">"Zezwalaj aplikacji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> na dostęp do kalendarza"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
- <string name="permgroupdesc_sms" msgid="4656988620100940350">"wysyłanie i wyświetlanie SMS-ów"</string>
+ <string name="permgroupdesc_sms" msgid="4656988620100940350">"wysyłanie i wyświetlanie SMS‑ów"</string>
<string name="permgrouprequest_sms" msgid="605618939583628306">"Zezwalaj aplikacji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> na wysyłanie i wyświetlanie SMS-ów"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Pamięć wewnętrzna"</string>
<string name="permgroupdesc_storage" msgid="637758554581589203">"dostęp do zdjęć, multimediów i plików na Twoim urządzeniu"</string>
@@ -1091,6 +1091,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Włącz ponownie, wybierając Ustawienia systemowe > Aplikacje > Pobrane."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje obecnie ustawionego rozmiaru wyświetlacza i może działać niestabilnie."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Zawsze pokazuj"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> została skompilowana pod niezgodną wersję systemu Android i może zachowywać się niezgodnie z oczekiwaniami. Sprawdź, czy jest dostępna zaktualizowana wersja aplikacji."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Zawsze pokazuj"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Sprawdź aktualizację"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) naruszyła wymuszone przez siebie zasady StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> naruszył wymuszone przez siebie zasady StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android jest uaktualniany..."</string>
@@ -1160,10 +1163,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Zaloguj się do sieci"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Sieć Wi-Fi nie ma dostępu do internetu"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Sieć Wi-Fi nie ma dostępu do internetu"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Kliknij, by wyświetlić opcje"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Zmieniono na połączenie typu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Urządzenie korzysta z połączenia typu <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, gdy <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nie dostępu do internetu. Mogą zostać naliczone opłaty."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Urządzenie korzysta z połączenia typu <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, gdy <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nie dostępu do internetu. Mogą zostać naliczone opłaty."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Przełączono z połączenia typu <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>."</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobilna transmisja danych"</item>
@@ -1174,7 +1177,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nieznany typ sieci"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nie można połączyć się z siecią Wi-Fi."</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ma powolne połączenie internetowe."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ma powolne połączenie internetowe."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Zezwolić na połączenie?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacja %1$s chce połączyć się z siecią Wi-Fi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikacja"</string>
@@ -1684,7 +1687,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Zainstalowany przez administratora"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Zaktualizowany przez administratora"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Usunięty przez administratora"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Aby wydłużyć czas pracy baterii, Oszczędzanie baterii ogranicza aktywność urządzenia, w tym wibracje, usługi lokalizacyjne i przetwarzanie większości danych w tle. Poczta, czat i inne synchronizowane aplikacje mogą nie aktualizować swojej zawartości, dopóki ich nie otworzysz.\n\nOszczędzanie baterii wyłącza się automatycznie podczas ładowania urządzenia."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Aby wydłużyć czas pracy baterii, Oszczędzanie baterii ogranicza aktywność urządzenia, w tym wibracje, usługi lokalizacyjne i przetwarzanie większości danych w tle. Poczta, SMS-y i inne synchronizowane aplikacje mogą nie aktualizować swojej zawartości, dopóki ich nie otworzysz.\n\nOszczędzanie baterii wyłącza się automatycznie podczas ładowania urządzenia."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Oszczędzanie danych uniemożliwia niektórym aplikacjom wysyłanie i odbieranie danych w tle, zmniejszając w ten sposób ich użycie. Aplikacja, z której w tej chwili korzystasz, może uzyskiwać dostęp do danych, ale rzadziej. Może to powodować, że obrazy będą się wyświetlać dopiero po kliknięciu."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Włączyć Oszczędzanie danych?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Włącz"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 03c4536a..a6b389e 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Sem serviço de voz/emergência"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Serviço temporariamente bloqueado pela rede móvel no seu local"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Não foi possível acessar a rede"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Para melhorar a recepção, tente alterar o tipo selecionado em Configurações > Rede & Internet > Redes móveis > Tipo de rede preferencial."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Para melhorar a recepção, tente alterar o tipo selecionado em Config. > Rede e Internet > Redes móveis > Tipo de rede preferencial."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"A chamada no Wi‑Fi está ativa"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"As chamadas de emergência exigem uma rede móvel."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Alertas"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reativar isso em Configurações do sistema > Apps > Transferidos."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com a configuração atual de tamanho de exibição e pode se comportar de forma inesperada."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> foi criado para uma versão incompatível do sistema operacional Android e pode se comportar de forma inesperada. Uma versão atualizada do app pode estar disponível."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Mostrar sempre"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Verificar atualizações"</string>
<string name="smv_application" msgid="3307209192155442829">"O app <xliff:g id="APPLICATION">%1$s</xliff:g>, processo <xliff:g id="PROCESS">%2$s</xliff:g>, violou a política StrictMode imposta automaticamente."</string>
<string name="smv_process" msgid="5120397012047462446">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> violou a política StrictMode imposta automaticamente."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"O Android está sendo atualizado..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Fazer login na rede"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"O Wi-Fi não tem acesso à Internet"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"O Wi‑Fi não tem acesso à Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toque para ver opções"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Cobranças podem ser aplicadas."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Esse serviço pode ser cobrado."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"dados móveis"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"um tipo de rede desconhecido"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível se conectar a redes Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tem uma conexão de baixa qualidade com a Internet."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" tem uma conexão de baixa qualidade com a Internet."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir conexão?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"O app %1$s deseja se conectar à rede Wi-Fi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Um app"</string>
@@ -1634,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Instalado pelo seu administrador"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Atualizado pelo seu administrador"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Excluído pelo seu administrador"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"A economia de bateria reduz o desempenho do dispositivo e limita a vibração, os serviços de localização e a maioria dos dados em segundo plano para aumentar a duração da bateria. E-mails, mensagens e outros apps que dependem de sincronização não serão atualizados, a não ser que você os abra.\n\nA economia de bateria é desligada automaticamente quando o dispositivo está sendo carregado."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Para ajudar a melhorar a duração da bateria, a Economia de bateria reduz o desempenho do seu dispositivo e limita a vibração, os serviços de localização e a maioria dos dados em segundo plano. E-mails, mensagens e outros apps que dependem da sincronização podem não ser atualizados, a menos que você os abra.\n\nA Economia de bateria é desativada automaticamente quando o dispositivo está sendo carregado."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode significar que as imagens não serão exibidas até que você toque nelas."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Ativar Economia de dados?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Ativar"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 2de83c6..3329961 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -47,8 +47,8 @@
<string name="needPuk2" msgid="4526033371987193070">"Introduza o PUK2 para desbloquear o cartão SIM."</string>
<string name="enablePin" msgid="209412020907207950">"Ação sem êxito. Ative o bloqueio do SIM/RUIM."</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
- <item quantity="one">Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar bloqueado.</item>
<item quantity="other">Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar bloqueado.</item>
+ <item quantity="one">Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar bloqueado.</item>
</plurals>
<string name="imei" msgid="2625429890869005782">"IMEI"</string>
<string name="meid" msgid="4841221237681254195">"MEID"</string>
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Sem serviço de voz/emergência"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Serviço temporariamente não disponibilizado pela rede móvel na sua localização"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Não é possível ligar à rede"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Para melhorar a receção, experimente alterar o tipo selecionado em Definições > Rede e Internet > Redes móveis > Tipo de rede preferido."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Para melhorar a receção, experimente alterar o tipo selecionado em Definições > Rede e Internet > Redes móveis > Tipo de rede preferido."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"As chamadas Wi‑Fi estão ativas."</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"As chamadas de emergência necessitam de uma rede móvel."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Alertas"</string>
@@ -162,8 +162,8 @@
<string name="low_memory" product="tv" msgid="516619861191025923">"O armazenamento da TV está cheio. Elimine alguns ficheiros para libertar espaço."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"O armazenamento do telemóvel está cheio. Elimine alguns ficheiros para libertar espaço."</string>
<plurals name="ssl_ca_cert_warning" formatted="false" msgid="5106721205300213569">
- <item quantity="one">Autoridade de certificação instalada</item>
<item quantity="other">Autoridades de certificação instaladas</item>
+ <item quantity="one">Autoridade de certificação instalada</item>
</plurals>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Por um terceiro desconhecido"</string>
<string name="ssl_ca_cert_noti_by_administrator" msgid="3541729986326153557">"Pelo gestor do seu perfil de trabalho"</string>
@@ -212,6 +212,8 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Desligar"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Emergência"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Relatório de erros"</string>
+ <!-- no translation found for global_action_logout (935179188218826050) -->
+ <skip />
<string name="bugreport_title" msgid="2667494803742548533">"Criar relatório de erros"</string>
<string name="bugreport_message" msgid="398447048750350456">"Será recolhida informação sobre o estado atual do seu dispositivo a enviar através de uma mensagem de email. Demorará algum tempo até que o relatório de erro esteja pronto para ser enviado. Aguarde um pouco."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Relatório interativo"</string>
@@ -219,8 +221,8 @@
<string name="bugreport_option_full_title" msgid="6354382025840076439">"Relatório completo"</string>
<string name="bugreport_option_full_summary" msgid="7210859858969115745">"Utilize esta opção para uma interferência mínima do sistema quando o dispositivo não responder ou estiver demasiado lento, ou quando precisar de todas as secções de relatório. Não permite introduzir mais detalhes ou tirar capturas de ecrã adicionais."</string>
<plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
- <item quantity="one">A tirar uma captura de ecrã do relatório de erro dentro de <xliff:g id="NUMBER_0">%d</xliff:g> segundo…</item>
<item quantity="other">A tirar uma captura de ecrã do relatório de erro dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
+ <item quantity="one">A tirar uma captura de ecrã do relatório de erro dentro de <xliff:g id="NUMBER_0">%d</xliff:g> segundo…</item>
</plurals>
<string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencioso"</string>
<string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Som desativado"</string>
@@ -864,8 +866,8 @@
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Há 1 mês"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Há mais de 1 mês"</string>
<plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
- <item quantity="one">Último <xliff:g id="COUNT_0">%d</xliff:g> dia</item>
<item quantity="other">Últimos <xliff:g id="COUNT_1">%d</xliff:g> dias</item>
+ <item quantity="one">Último <xliff:g id="COUNT_0">%d</xliff:g> dia</item>
</plurals>
<string name="last_month" msgid="3959346739979055432">"Último mês"</string>
<string name="older" msgid="5211975022815554840">"Mais antiga"</string>
@@ -886,68 +888,68 @@
<string name="years" msgid="6881577717993213522">"anos"</string>
<string name="now_string_shortest" msgid="8912796667087856402">"agora"</string>
<plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
- <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> m</item>
<item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> m</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> m</item>
</plurals>
<plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
- <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> h</item>
<item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> h</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> h</item>
</plurals>
<plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
- <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> d</item>
<item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> d</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> d</item>
</plurals>
<plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
- <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> a</item>
<item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> a</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> a</item>
</plurals>
<plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
- <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> min</item>
<item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> min</item>
+ <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> min</item>
</plurals>
<plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
- <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> h</item>
<item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> h</item>
+ <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> h</item>
</plurals>
<plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
- <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> d</item>
<item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> d</item>
+ <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> d</item>
</plurals>
<plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
- <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> a</item>
<item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> a</item>
+ <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> a</item>
</plurals>
<plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
- <item quantity="one">há <xliff:g id="COUNT_0">%d</xliff:g> minuto</item>
<item quantity="other">há <xliff:g id="COUNT_1">%d</xliff:g> minutos</item>
+ <item quantity="one">há <xliff:g id="COUNT_0">%d</xliff:g> minuto</item>
</plurals>
<plurals name="duration_hours_relative" formatted="false" msgid="676894109982008411">
- <item quantity="one">há <xliff:g id="COUNT_0">%d</xliff:g> hora</item>
<item quantity="other">há <xliff:g id="COUNT_1">%d</xliff:g> horas</item>
+ <item quantity="one">há <xliff:g id="COUNT_0">%d</xliff:g> hora</item>
</plurals>
<plurals name="duration_days_relative" formatted="false" msgid="2203515825765397130">
- <item quantity="one">há <xliff:g id="COUNT_0">%d</xliff:g> dia</item>
<item quantity="other">há <xliff:g id="COUNT_1">%d</xliff:g> dias</item>
+ <item quantity="one">há <xliff:g id="COUNT_0">%d</xliff:g> dia</item>
</plurals>
<plurals name="duration_years_relative" formatted="false" msgid="4820062134188885734">
- <item quantity="one">há <xliff:g id="COUNT_0">%d</xliff:g> ano</item>
<item quantity="other">há <xliff:g id="COUNT_1">%d</xliff:g> anos</item>
+ <item quantity="one">há <xliff:g id="COUNT_0">%d</xliff:g> ano</item>
</plurals>
<plurals name="duration_minutes_relative_future" formatted="false" msgid="4655043589817680966">
- <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> minuto</item>
<item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> minutos</item>
+ <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> minuto</item>
</plurals>
<plurals name="duration_hours_relative_future" formatted="false" msgid="8084579714205223891">
- <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> hora</item>
<item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> horas</item>
+ <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> hora</item>
</plurals>
<plurals name="duration_days_relative_future" formatted="false" msgid="333215369363433992">
- <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> dia</item>
<item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> dias</item>
+ <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> dia</item>
</plurals>
<plurals name="duration_years_relative_future" formatted="false" msgid="8644862986413104011">
- <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> ano</item>
<item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> anos</item>
+ <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> ano</item>
</plurals>
<string name="VideoView_error_title" msgid="3534509135438353077">"Problema com o vídeo"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Este vídeo não é válido para transmissão em fluxo contínuo neste aparelho."</string>
@@ -1051,6 +1053,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reative este modo nas Definições do Sistema > Aplicações > Transferidas."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> não suporta a definição de Tamanho do ecrã atual e pode ter um comportamento inesperado."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"A aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> foi concebida para uma versão incompatível do SO Android e pode ter um comportamento inesperado. Pode estar disponível uma versão atualizada da aplicação."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Mostrar sempre"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Verificar se existem atualizações"</string>
<string name="smv_application" msgid="3307209192155442829">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) violou a política StrictMode auto-imposta."</string>
<string name="smv_process" msgid="5120397012047462446">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> violou a política StrictMode auto-imposta."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"O Android está a ser atualizado..."</string>
@@ -1098,12 +1103,12 @@
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notificação"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"Desconhecido"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
- <item quantity="one">Rede Wi-Fi disponível</item>
<item quantity="other">Redes Wi-Fi disponíveis</item>
+ <item quantity="one">Rede Wi-Fi disponível</item>
</plurals>
<plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
- <item quantity="one">Rede Wi-Fi aberta disponível</item>
<item quantity="other">Redes Wi-Fi abertas disponíveis</item>
+ <item quantity="one">Rede Wi-Fi aberta disponível</item>
</plurals>
<string name="wifi_available_title" msgid="3817100557900599505">"Ligar à rede Wi-Fi aberta"</string>
<string name="wifi_available_title_connecting" msgid="1557292688310330032">"A ligar à rede Wi-Fi aberta…"</string>
@@ -1116,10 +1121,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Início de sessão na rede"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"O Wi-Fi não tem acesso à Internet"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"O Wi-Fi não tem acesso à Internet."</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toque para obter mais opções"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Mudou para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Podem ser aplicados custos."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Podem aplicar-se custos."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Mudou de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"dados móveis"</item>
@@ -1130,7 +1135,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"um tipo de rede desconhecido"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível ligar a Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tem uma ligação à internet fraca."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" tem uma ligação à internet fraca."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir ligação?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"A aplicação %1$s pretende estabelecer ligação à rede Wi-Fi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Uma aplicação"</string>
@@ -1317,8 +1322,8 @@
<string name="no_matches" msgid="8129421908915840737">"Sem correspondências"</string>
<string name="find_on_page" msgid="1946799233822820384">"Localizar na página"</string>
<plurals name="matches_found" formatted="false" msgid="1210884353962081884">
- <item quantity="one">1 correspondência</item>
<item quantity="other"><xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g></item>
+ <item quantity="one">1 correspondência</item>
</plurals>
<string name="action_mode_done" msgid="7217581640461922289">"Concluído"</string>
<string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"A apagar memória de armazenamento USB..."</string>
@@ -1452,8 +1457,8 @@
<string name="kg_wrong_password" msgid="2333281762128113157">"Palavra-passe Incorreta"</string>
<string name="kg_wrong_pin" msgid="1131306510833563801">"PIN Incorreto"</string>
<plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="8790651267324125694">
- <item quantity="one">Tente novamente dentro de 1 segundo.</item>
<item quantity="other">Tente novamente dentro de <xliff:g id="NUMBER">%d</xliff:g> segundos.</item>
+ <item quantity="one">Tente novamente dentro de 1 segundo.</item>
</plurals>
<string name="kg_pattern_instructions" msgid="398978611683075868">"Desenhe a sua sequência"</string>
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduzir PIN do cartão SIM"</string>
@@ -1495,6 +1500,10 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Quando o atalho está ativado, premir ambos os botões de volume durante 3 segundos inicia uma funcionalidade de acessibilidade.\n\n Funcionalidade de acessibilidade atual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Pode alterar a funcionalidade em Definições > Acessibilidade."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Desativar atalho"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Utilizar atalho"</string>
+ <!-- no translation found for color_inversion_feature_name (4231186527799958644) -->
+ <skip />
+ <!-- no translation found for color_correction_feature_name (6779391426096954933) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O Atalho de acessibilidade ativou o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O Atalho de acessibilidade desativou o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolha uma funcionalidade para utilizar quando tocar no botão Acessibilidade:"</string>
@@ -1607,8 +1616,8 @@
<string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Os PINs não correspondem. Tente novamente."</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"O PIN é demasiado pequeno. Deve ter, no mínimo, 4 dígitos."</string>
<plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
- <item quantity="one">Tente novamente dentro de 1 segundo</item>
<item quantity="other">Tente novamente dentro de <xliff:g id="COUNT">%d</xliff:g> segundos</item>
+ <item quantity="one">Tente novamente dentro de 1 segundo</item>
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"Tente novamente mais tarde"</string>
<string name="immersive_cling_title" msgid="8394201622932303336">"Visualização de ecrã inteiro"</string>
@@ -1634,41 +1643,41 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Instalado pelo seu gestor"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Atualizado pelo seu gestor"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Eliminado pelo seu gestor"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Para ajudar a melhorar a autonomia da bateria, a poupança de bateria reduz o desempenho do seu dispositivo e limita a vibração, os serviços de localização e a maioria dos dados em segundo plano. O email, as mensagens e outras aplicações que dependem da sincronização não podem ser atualizados exceto se os abrir.\n\nA poupança de bateria desliga-se automaticamente quando o dispositivo está a carregar."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Para ajudar a melhorar a autonomia da bateria, a Poupança de bateria reduz o desempenho do seu dispositivo e limita a vibração, os serviços de localização e a maioria dos dados em segundo plano. O email, as mensagens e outras aplicações que dependem da sincronização poderão não ser atualizados, exceto se os abrir.\n\nA Poupança de bateria desliga-se automaticamente quando o dispositivo está a carregar."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Para ajudar a reduzir a utilização de dados, a Poupança de dados impede que algumas aplicações enviem ou recebam dados em segundo plano. Uma determinada aplicação que esteja a utilizar atualmente pode aceder aos dados, mas é possível que o faça com menos frequência. Isto pode significar, por exemplo, que as imagens não são apresentadas até que toque nas mesmas."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Ativar a Poupança de dados?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Ativar"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
- <item quantity="one">Durante um minuto (até à(s) <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
<item quantity="other">Durante %1$d minutos (até à(s) <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="one">Durante um minuto (até à(s) <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
</plurals>
<plurals name="zen_mode_duration_minutes_summary_short" formatted="false" msgid="6830154222366042597">
- <item quantity="one">Durante 1 min (até à(s) <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
<item quantity="other">Durante %1$d min (até à(s) <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="one">Durante 1 min (até à(s) <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
</plurals>
<plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
- <item quantity="one">Durante uma hora (até à(s) <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
<item quantity="other">Durante %1$d horas (até à(s) <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="one">Durante uma hora (até à(s) <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
</plurals>
<plurals name="zen_mode_duration_hours_summary_short" formatted="false" msgid="4787552595253082371">
- <item quantity="one">Durante 1 h (até à(s) <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
<item quantity="other">Durante %1$d h (até à(s) <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="one">Durante 1 h (até à(s) <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
</plurals>
<plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
- <item quantity="one">Durante um minuto</item>
<item quantity="other">Durante %d minutos</item>
+ <item quantity="one">Durante um minuto</item>
</plurals>
<plurals name="zen_mode_duration_minutes_short" formatted="false" msgid="2199350154433426128">
- <item quantity="one">Durante 1 min</item>
<item quantity="other">Durante %d min</item>
+ <item quantity="one">Durante 1 min</item>
</plurals>
<plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
- <item quantity="one">Durante uma hora</item>
<item quantity="other">Durante %d horas</item>
+ <item quantity="one">Durante uma hora</item>
</plurals>
<plurals name="zen_mode_duration_hours_short" formatted="false" msgid="6748277774662434217">
- <item quantity="one">Durante 1 h</item>
<item quantity="other">Durante %d h</item>
+ <item quantity="one">Durante 1 h</item>
</plurals>
<string name="zen_mode_until" msgid="7336308492289875088">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_alarm" msgid="9128205721301330797">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
@@ -1681,6 +1690,8 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Dias da semana à noite"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Fim de semana"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Evento"</string>
+ <!-- no translation found for zen_mode_default_every_night_name (3012363838882944175) -->
+ <skip />
<string name="muted_by" msgid="6147073845094180001">"Som desativado por <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Existe um problema interno no seu dispositivo e pode ficar instável até efetuar uma reposição de dados de fábrica."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Existe um problema interno no seu dispositivo. Contacte o fabricante para obter mais informações."</string>
@@ -1703,8 +1714,8 @@
<string name="close_button_text" msgid="3937902162644062866">"Fechar"</string>
<string name="notification_messaging_title_template" msgid="3452480118762691020">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
<plurals name="selected_count" formatted="false" msgid="7187339492915744615">
- <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selecionado</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selecionado</item>
</plurals>
<string name="default_notification_channel_label" msgid="5929663562028088222">"Sem categoria"</string>
<string name="importance_from_user" msgid="7318955817386549931">"Definiu a importância destas notificações."</string>
@@ -1761,8 +1772,8 @@
<string name="autofill_error_cannot_autofill" msgid="7402758580060110371">"Não é possível preencher automaticamente o conteúdo"</string>
<string name="autofill_picker_no_suggestions" msgid="3908514303773350735">"Sem sugestões do preenchimento automático"</string>
<plurals name="autofill_picker_some_suggestions" formatted="false" msgid="5506565809835815274">
- <item quantity="one">Uma sugestão do preenchimento automático</item>
<item quantity="other"><xliff:g id="COUNT">%1$s</xliff:g> sugestões do preenchimento automático</item>
+ <item quantity="one">Uma sugestão do preenchimento automático</item>
</plurals>
<string name="autofill_save_title" msgid="3345527308992082601">"Pretende guardar no <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string>
<string name="autofill_save_title_with_type" msgid="8637809388029313305">"Pretende guardar <xliff:g id="TYPE">%1$s</xliff:g> no <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 03c4536a..a6b389e 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Sem serviço de voz/emergência"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Serviço temporariamente bloqueado pela rede móvel no seu local"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Não foi possível acessar a rede"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Para melhorar a recepção, tente alterar o tipo selecionado em Configurações > Rede & Internet > Redes móveis > Tipo de rede preferencial."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Para melhorar a recepção, tente alterar o tipo selecionado em Config. > Rede e Internet > Redes móveis > Tipo de rede preferencial."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"A chamada no Wi‑Fi está ativa"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"As chamadas de emergência exigem uma rede móvel."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Alertas"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reativar isso em Configurações do sistema > Apps > Transferidos."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com a configuração atual de tamanho de exibição e pode se comportar de forma inesperada."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> foi criado para uma versão incompatível do sistema operacional Android e pode se comportar de forma inesperada. Uma versão atualizada do app pode estar disponível."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Mostrar sempre"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Verificar atualizações"</string>
<string name="smv_application" msgid="3307209192155442829">"O app <xliff:g id="APPLICATION">%1$s</xliff:g>, processo <xliff:g id="PROCESS">%2$s</xliff:g>, violou a política StrictMode imposta automaticamente."</string>
<string name="smv_process" msgid="5120397012047462446">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> violou a política StrictMode imposta automaticamente."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"O Android está sendo atualizado..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Fazer login na rede"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"O Wi-Fi não tem acesso à Internet"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"O Wi‑Fi não tem acesso à Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toque para ver opções"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Cobranças podem ser aplicadas."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Esse serviço pode ser cobrado."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"dados móveis"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"um tipo de rede desconhecido"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível se conectar a redes Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tem uma conexão de baixa qualidade com a Internet."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" tem uma conexão de baixa qualidade com a Internet."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir conexão?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"O app %1$s deseja se conectar à rede Wi-Fi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Um app"</string>
@@ -1634,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Instalado pelo seu administrador"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Atualizado pelo seu administrador"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Excluído pelo seu administrador"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"A economia de bateria reduz o desempenho do dispositivo e limita a vibração, os serviços de localização e a maioria dos dados em segundo plano para aumentar a duração da bateria. E-mails, mensagens e outros apps que dependem de sincronização não serão atualizados, a não ser que você os abra.\n\nA economia de bateria é desligada automaticamente quando o dispositivo está sendo carregado."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Para ajudar a melhorar a duração da bateria, a Economia de bateria reduz o desempenho do seu dispositivo e limita a vibração, os serviços de localização e a maioria dos dados em segundo plano. E-mails, mensagens e outros apps que dependem da sincronização podem não ser atualizados, a menos que você os abra.\n\nA Economia de bateria é desativada automaticamente quando o dispositivo está sendo carregado."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode significar que as imagens não serão exibidas até que você toque nelas."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Ativar Economia de dados?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Ativar"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index d65eaa7..8e3726b 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -80,7 +80,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Fără servicii vocale/de urgență"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Momentan nu este oferit de rețeaua mobilă în locația dvs."</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Nu se poate stabili conexiunea la rețea"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Pentru o recepție mai bună, încercați să schimbați tipul selectat în Setări > Rețea și internet > Rețele mobile > Tip preferat de rețea."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Pentru o recepție mai bună, încercați să schimbați tipul selectat în Setări > Rețea și internet > Rețele mobile > Tip preferat de rețea."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Apelarea prin Wi-Fi este activă"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Apelurile de urgență necesită o rețea mobilă."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Alerte"</string>
@@ -1071,6 +1071,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reactivați acest mod din Setări de sistem > Aplicații > Descărcate."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu acceptă setarea actuală pentru Dimensiunea afișării și este posibil să aibă un comportament neașteptat."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Afișează întotdeauna"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> a fost concepută pentru o versiune incompatibilă de sistem de operare Android și este posibil să se comporte în mod neprevăzut. Poate fi disponibilă o versiune actualizată a aplicației."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Afișați întotdeauna"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Căutați actualizări"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplicația <xliff:g id="APPLICATION">%1$s</xliff:g> (procesul <xliff:g id="PROCESS">%2$s</xliff:g>) a încălcat propria politică StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Procesul <xliff:g id="PROCESS">%1$s</xliff:g> a încălcat propria politică StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android trece la o versiune superioară..."</string>
@@ -1138,10 +1141,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Conectați-vă la rețea"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Rețeaua Wi-Fi nu are acces la internet"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Rețeaua Wi-Fi nu are acces la internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Atingeți pentru opțiuni"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"S-a comutat la <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Dispozitivul folosește <xliff:g id="NEW_NETWORK">%1$s</xliff:g> când <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nu are acces la internet. Se pot aplica taxe."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Dispozitivul folosește <xliff:g id="NEW_NETWORK">%1$s</xliff:g> când <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nu are acces la internet. Se pot aplica taxe."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"S-a comutat de la <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> la <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"date mobile"</item>
@@ -1152,7 +1155,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un tip de rețea necunoscut"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nu se poate conecta la Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" are o conexiune la internet slabă."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" are o conexiune la internet slabă."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permiteți conectarea?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplicația %1$s dorește să se conecteze la rețeaua Wi-Fi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"O aplicație"</string>
@@ -1659,7 +1662,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Instalat de administratorul dvs."</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Actualizat de administratorul dvs."</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Șters de administratorul dvs."</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Pentru a îmbunătăți autonomia bateriei, funcția de economisire a energiei reduce performanțele dispozitivului și limitează vibrațiile, serviciile de localizare și majoritatea datelor de fundal. Este posibil ca e-mailurile, mesageria și alte aplicații care depind de sincronizare să nu se actualizeze dacă nu le deschideți.\n\nFuncția de economisire a energiei se dezactivează automat când dispozitivul se încarcă."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Pentru a îmbunătăți autonomia bateriei, economisirea bateriei reduce performanțele dispozitivului și limitează vibrațiile, serviciile de localizare și majoritatea datelor de fundal. Este posibil ca e-mailurile, mesageria și alte aplicații care depind de sincronizare să nu se actualizeze dacă nu le deschideți.\n\nEconomisirea bateriei se dezactivează automat când dispozitivul se încarcă."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Pentru a contribui la reducerea utilizării de date, Economizorul de date împiedică unele aplicații să trimită sau să primească date în fundal. O aplicație pe care o folosiți poate accesa datele, însă mai rar. Aceasta poate însemna, de exemplu, că imaginile se afișează numai după ce le atingeți."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Activați Economizorul de date?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Activați"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index fc9298c..f8ebf0d 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -81,7 +81,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Голосовые и экстренные вызовы недоступны"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Местная мобильная сеть временно не поддерживает эту функцию."</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Сеть недоступна"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Чтобы улучшить сигнал, попробуйте выбрать другой тип сети в настройках (раздел \"Мобильные сети\")."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Чтобы улучшить сигнал, попробуйте выбрать другой тип сети в настройках (раздел \"Мобильные сети\")."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Включена функция \"Звонки по Wi‑Fi\""</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Для экстренных вызовов требуется мобильная сеть."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Оповещения"</string>
@@ -1091,6 +1091,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Включить эту функцию можно в меню \"Настройки > Приложения > Загруженные\"."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" не поддерживает выбранный масштаб изображения на экране и может работать некорректно."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Всегда показывать"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" было разработано для несовместимой версии ОС Android и может работать некорректно. Рекомендуем скачать новую версию приложения."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Всегда показывать"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Проверить обновления"</string>
<string name="smv_application" msgid="3307209192155442829">"Приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" (процесс: <xliff:g id="PROCESS">%2$s</xliff:g>) нарушило собственную политику StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Процесс <xliff:g id="PROCESS">%1$s</xliff:g> нарушил собственную политику StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Обновление Android..."</string>
@@ -1160,10 +1163,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Регистрация в сети"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Сеть Wi-Fi не подключена к Интернету"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Сеть Wi-Fi не подключена к Интернету"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Нажмите, чтобы показать варианты."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Новое подключение: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Устройство использует <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, если подключение к сети <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> недоступно. Может взиматься плата за передачу данных."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Устройство использует <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, если подключение к сети <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> недоступно. Может взиматься плата за передачу данных."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Устройство отключено от сети <xliff:g id="NEW_NETWORK">%2$s</xliff:g> и теперь использует <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"мобильный Интернет"</item>
@@ -1174,7 +1177,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"неизвестный тип сети"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не удалось подключиться к сети Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" – плохое интернет-соединение."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" – плохое интернет-соединение."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Разрешить подключение?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Приложение \"%1$s\" запрашивает доступ на подключение к сети Wi-Fi (%2$s)"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Приложение"</string>
@@ -1676,7 +1679,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Задача 2: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Задача 3: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Чтобы открепить экран, нажмите и удерживайте кнопки \"Назад\" и \"Обзор\""</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Это приложение нельзя открепить"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Блокировка включена"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Блокировка выключена"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"PIN-код для отключения"</string>
@@ -1685,7 +1687,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Установлено администратором"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Обновлено администратором"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Удалено администратором"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Чтобы продлить время работы устройства от батареи, в режиме энергосбережения снижается производительность, а также ограничивается использование вибрации, геолокации и фоновой передачи данных. Данные, требующие синхронизации, могут обновляться только когда вы откроете приложение.\n\nРежим энергосбережения автоматически отключается во время зарядки устройства."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Чтобы продлить время работы устройства от батареи, в режиме энергосбережения снижается производительность, а также ограничивается использование вибросигнала, геолокации и фоновой передачи данных. Данные, требующие синхронизации, могут обновляться только после того, как вы откроете приложение.\n\nРежим энергосбережения автоматически отключается во время зарядки устройства."</string>
<string name="data_saver_description" msgid="6015391409098303235">"В режиме экономии трафика фоновая передача для некоторых приложений отключена. Приложение, которым вы пользуетесь, может получать и отправлять данные, но реже, чем обычно. Например, изображения могут не загружаться, пока вы не нажмете на них."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Включить экономию трафика?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Включить"</string>
@@ -1744,7 +1746,7 @@
<string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g> / <xliff:g id="REST">%2$s</xliff:g>"</string>
<string name="toolbar_collapse_description" msgid="2821479483960330739">"Свернуть"</string>
<string name="zen_mode_feature_name" msgid="5254089399895895004">"Не беспокоить"</string>
- <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"Режим оповещения"</string>
+ <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"Режим уведомления"</string>
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Будний вечер"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Выходные"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Мероприятие"</string>
@@ -1852,14 +1854,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Тестовое экстренное сообщение"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Ответить"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"Для SIM-карты недоступны голосовые вызовы"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM-карта не активирована для голосовых вызовов"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"Для SIM-карты недоступны голосовые вызовы"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Для телефона недоступны голосовые вызовы"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Всплывающее окно"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Требуется последняя версия приложения"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 9eff25e..af1f8ba 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"හඬ/හදිසි සේවාව නොමැත"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"ඔබේ ස්ථානයේ ජංගම ජාලය මගින් තාවකාලිකව පිරිනොනමයි"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"ජාලය වෙත ළඟා විය නොහැකිය"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"ප්රතිග්රහණය වැඩි දියුණු කිරීමට, සැකසීම් > ජාලය සහ අන්තර්ජාලය > ජංගම ජාල > වඩා කැමති ජාල වර්ගය තුළ තෝරන ලද වර්ගය වෙනස් කිරීම උත්සාහ කරන්න."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"ප්රතිග්රහණය වැඩි දියුණු කිරීමට, සැකසීම් > ජාලය සහ අන්තර්ජාලය > ජංගම ජාල > වඩා කැමති ජාල වර්ගය තුළ තෝරන ලද වර්ගය වෙනස් කිරීම උත්සාහ කරන්න."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi ඇමතීම සක්රියයි"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"හදිසි ඇමතුම්වලට ජංගම ජාලයක් අවශ්යයි"</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"ඇඟවීම්"</string>
@@ -1053,6 +1053,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"පද්ධති සැකසීම් තුළ මෙය නැවත ක්රියාත්මක කරන්න > යෙදුම් > බාගන්නා ලදි."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> වත්මන් සංදර්ශක තරම සඳහා සහාය නොදක්වන අතර අනපේක්ෂිත ලෙස හැසිරීමට හැකිය."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"සැම විටම පෙන්වන්න"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> Android OS හි නොගැළපෙන අනුවාදයක් සඳහා තනන ලද අතර අනපේක්ෂිත ලෙස හැසිරිය හැකිය. යෙදුමේ යාවත්කාලීන අනුවාදයක් ලබා ගත හැකිය."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"සැම විටම පෙන්වන්න"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"යාවත්කාලීන සඳහා පරික්ෂා කරන්න"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> යෙදුම (<xliff:g id="PROCESS">%2$s</xliff:g> ක්රියාවලිය) එහි StrictMode කොන්දේසිය උල්ලංඝනය කර ඇත."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> ක්රියාවලිය එහි StrictMode කොන්දේසිය උල්ලංඝනය කර ඇත."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android උත්ශ්රේණි වෙමින් පවතී..."</string>
@@ -1118,10 +1121,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"ජාලයට පුරනය වන්න"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi හට අන්තර්ජාල ප්රවේශය නැත"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi සඳහා අන්තර්ජාල ප්රවේශය නැත"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"විකල්ප සඳහා තට්ටු කරන්න"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> වෙත මාරු විය"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"උපාංගය <xliff:g id="NEW_NETWORK">%1$s</xliff:g> <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> සඳහා අන්තර්ජාල ප්රවේශය නැති විට භාවිත කරයි. ගාස්තු අදාළ විය හැකිය."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"උපාංගය <xliff:g id="NEW_NETWORK">%1$s</xliff:g> <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> සඳහා අන්තර්ජාල ප්රවේශය නැති විට භාවිත කරයි. ගාස්තු අදාළ විය හැකිය."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> සිට <xliff:g id="NEW_NETWORK">%2$s</xliff:g> වෙත මාරු විය"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"ජංගම දත්ත"</item>
@@ -1132,7 +1135,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"නොදන්නා ජාල වර්ගයකි"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi වෙත සම්බන්ධ විය නොහැක"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" දුබල අන්තර්ජාල සම්බන්ධතාවයක් ඇත."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" වෙත දුර්වල අන්තර්ජාල සම්බන්ධතාවයක් ඇත."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"සම්බන්ධතාවයට ඉඩ දෙන්නද?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"යෙදුම් %1$s ක් WiFi ජාලය %2$s වෙත සම්බන්ධ කිරීමට කැමතියි"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"යෙදුම"</string>
@@ -1628,7 +1631,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2වන වැඩ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3වන වැඩ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"මෙම තිර ඇමුණුම ගැලවීමට, දළ විශ්ලේෂණය බොත්තම් ස්පර්ශ කර අල්ලා ගෙන සිටින්න"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"මෙම යෙදුම් ඇමිණුම ගැලවීමට නොහැක"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"තිරය අගුළු දමා ඇත"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"තිරයේ අගුළු ඇර ඇත"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ගැලවීමට පෙර PIN විමසන්න"</string>
@@ -1637,7 +1639,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"ඔබගේ පරිපාලක මඟින් ස්ථාපනය කර ඇත"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"ඔබගේ පරිපාලක මඟින් යාවත්කාලීන කර ඇත"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"ඔබගේ පරිපාලක මඟින් මකා දමා ඇත"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"බැටරි ආයු කාලය වැඩිදියුණු කිරීමට උදවු කිරීමට, බැටරි සුරැකුම ඔබේ උපාංගයේ ක්රියාකාරීත්වය අඩුකරන අතර කම්පනය, පිහිටීම් සේවා, සහ බොහෝමයක් පසුබිම් දත්ත සීමා කරයි. ඔබ ඒවා විවෘත නොකරන්නේ නම් මිස ඊ-තැපැල්, පණිවිඩකරණය, සහ සමමුහුර්ත කිරීම මත රඳා පවතින වෙනත් යෙදුම් යාවත්කාලීන නොවිය හැකිය.\n\nඔබේ උපාංගය ආරෝපණය වන විට බැටරි සුරැකුම ස්වයංක්රියව ක්රියාත්මක වේ."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"බැටරි ආයු කාලය වැඩිදියුණු කිරීමට උදවු කිරීමට, බැටරි සුරැකුම ඔබේ උපාංගයේ ක්රියාකාරීත්වය අඩුකරන අතර කම්පනය, පිහිටීම් සේවා, සහ බොහෝමයක් පසුබිම් දත්ත සීමා කරයි. ඔබ ඒවා විවෘත නොකරන්නේ නම් මිස ඊ-තැපැල්, පණිවිඩකරණය, සහ සමමුහුර්ත කිරීම මත රඳා පවතින වෙනත් යෙදුම් යාවත්කාලීන නොවිය හැකිය.\n\nඔබේ උපාංගය ආරෝපණය වන විට බැටරි සුරැකුම ස්වයංක්රියව ක්රියාත්මක වේ."</string>
<string name="data_saver_description" msgid="6015391409098303235">"දත්ත භාවිතය අඩු කිරීමට උදවු වීමට, දත්ත සුරැකුම සමහර යෙදුම් පසුබිමින් දත්ත යැවීම සහ ලබා ගැනීම වළක්වයි. ඔබ දැනට භාවිත කරන යෙදුමකට දත්ත වෙත පිවිසීමට හැකිය, නමුත් එසේ කරන්නේ කලාතුරකින් විය හැකිය. මෙයින් අදහස් වන්නේ, උදාහරණයක් ලෙස, එම රූප ඔබ ඒවාට තට්ටු කරන තෙක් සංදර්ශනය නොවන බවය."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"දත්ත සුරැකුම ක්රියාත්මක කරන්නද?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ක්රියාත්මක කරන්න"</string>
@@ -1784,14 +1786,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"හදිසි පණිවිඩ පරීක්ෂණය"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"පිළිතුරු දෙන්න"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM හඬ සඳහා ඉඩ නොදේ"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM හඬ සඳහා ප්රතිපාදන නොදේ"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM හඬ සඳහා ඉඩ නොදේ"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"දුරකථනය හඬ සඳහා ඉඩ නොදේ"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"උත්පතන කවුළුව"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"මෙම කෙටි මගට නවතම යෙදුම අවශ්යයි"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 9dacc7b..40979f9 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -81,7 +81,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Hlasové ani tiesňové volania nie sú k dispozícii"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Momentálne nie sú v ponuke mobilnej siete na vašom mieste"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Nepodarilo sa pripojiť k sieti"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Ak chcete vylepšiť príjem, skúste zmeniť vybraný typ v časti Nastavenia > Sieť a internet > Mobilné siete > Preferovaný typ siete."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Ak chcete vylepšiť príjem, skúste zmeniť vybraný typ v časti Nastavenia > Sieť a internet > Mobilné siete > Preferovaný typ siete."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Volanie cez Wi‑Fi je aktívne"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Tiesňové volania vyžadujú mobilnú sieť."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Upozornenia"</string>
@@ -1091,6 +1091,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Povoľte to znova v sekcii Nastavenia systému > Aplikácie > Stiahnuté súbory."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> aktuálne nastavenie veľkosti zobrazenia nepodporuje a môže sa správať neočakávane."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Vždy zobrazovať"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> bola zostavená pre nekompatibilnú verziu systému Android OS a môže sa správať neočakávane. Môže byť k dispozícii aktualizovaná verzia tejto aplikácie."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Vždy zobrazovať"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Skontrolovať dostupnosť aktualizácie"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikácia <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) porušila svoje vlastné vynútené pravidlá StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> porušil svoje vlastné vynútené pravidlá StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Prebieha inovácia systému Android..."</string>
@@ -1160,10 +1163,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Prihlásenie do siete"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Sieť Wi‑Fi nemá prístup k internetu"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Sieť Wi‑Fi nemá prístup k internetu"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Klepnutím získate možnosti"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Prepnuté na sieť: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Keď sieť <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nemá prístup k internetu, zariadenie používa sieť <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Môžu sa účtovať poplatky."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Keď <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nemá prístup k internetu, zariadenie používa <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Môžu sa účtovať poplatky."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Prepnuté zo siete <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sieť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobilné dáta"</item>
@@ -1174,7 +1177,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"neznámy typ siete"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nepodarilo sa pripojiť k sieti Wi‑Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" má nekvalitné internetové pripojenie."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" má nekvalitné internetové pripojenie."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Povoliť pripojenie?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikácia %1$s sa chce pripojiť k sieti Wi‑Fi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikácia"</string>
@@ -1676,7 +1679,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. <xliff:g id="LABEL">%1$s</xliff:g> do práce"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. <xliff:g id="LABEL">%1$s</xliff:g> do práce"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Ak chcete odopnúť túto obrazovku, klepnite na tlačidlá Späť a Prehľad a podržte ich"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Táto aplikácia sa nedá odopnúť"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Obrazovka bola pripnutá"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Obrazovka bola uvoľnená"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pred uvoľnením požiadať o číslo PIN"</string>
@@ -1685,7 +1687,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Nainštaloval správca"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Aktualizoval správca"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Odstránil správca"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Šetrič batérie zníži výkonnosť zariadenia a obmedzí vibrácie, služby určovania polohy a dátové prenosy na pozadí, aby predĺžil výdrž batérie. Pošta, čet a ďalšie aplikácie, ktoré sa spoliehajú na synchronizáciu, sa možno nebudú aktualizovať, dokiaľ ich neotvoríte.\n\nPri nabíjaní zariadenia sa šetrič batérie automaticky vypne."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Šetrič batérie zníži výkonnosť zariadenia a obmedzí vibrácie, služby určovania polohy a dátové prenosy na pozadí, aby predĺžil výdrž batérie. Pošta, odosielanie a prijímanie správ a ďalšie aplikácie, ktoré sú založené na synchronizácii, sa možno nebudú aktualizovať, dokým ich neotvoríte.\n\nPri nabíjaní zariadenia sa šetrič batérie automaticky vypne."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Šetrič dát bráni niektorým aplikáciám odosielať alebo prijímať dáta na pozadí s cieľom znížiť spotrebu dát. Aplikácia, ktorú momentálne používate, môže prenášať dáta, ale môže to robiť menej často. Znamená to napríklad, že sa nezobrazia obrázky, kým na ne neklepnete."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Chcete zapnúť šetrič dát?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Zapnúť"</string>
@@ -1852,14 +1854,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test tiesňových správ"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Odpovedať"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM karta nie je povolená pre hlas"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM karta nie je k dispozícii pre hlas"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM karta nie je povolená pre hlas"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefón nie je povolený pre hlas"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Automaticky otvárané okno"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Tento odkaz vyžaduje najnovšiu aplikáciu"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 722e88e..d8b2745 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -81,7 +81,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Ni storitve za glasovne klice / klice v sili"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Ta storitev trenutno ni na voljo v mobilnem omrežju na vaši lokaciji"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Povezave z omrežjem ni mogoče vzpostaviti"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Če želite izboljšati sprejem, poskusite zamenjati vrsto omrežja v »Nastavitve« > »Omrežje in internet« > »Mobilna omrežja« > »Prednostna vrsta omrežja«."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Če želite izboljšati sprejem, poskusite zamenjati vrsto omrežja v »Nastavitve« > »Omrežje in internet« > »Mobilna omrežja« > »Prednostna vrsta omrežja«."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Klicanje prek Wi-Fi-ja je aktivno"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Za klice v sili potrebujete mobilno omrežje."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Opozorila"</string>
@@ -1091,6 +1091,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Znova omogočite to v sistemskih nastavitvah > Aplikacije > Preneseno."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podpira trenutne nastavitve velikosti zaslona, kar lahko vodi v nepričakovano delovanje."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Vedno pokaži"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je bila ustvarjena za nezdružljivo različico operacijskega sistema Android, kar lahko vodi v nepričakovano delovanje. Morda je na voljo posodobljena različica aplikacije."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Vedno pokaži"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Preveri, ali je na voljo posodobitev"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) krši svoj samouveljavljiv pravilnik o strogem načinu."</string>
<string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> krši svoj samoizvedljivi pravilnik o strogem načinu."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Poteka nadgradnja Androida ..."</string>
@@ -1160,10 +1163,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Prijava v omrežje"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Omrežje Wi-Fi nima dostopa do interneta"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Omrežje Wi-Fi nima dostopa do interneta"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dotaknite se za možnosti"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Preklopljeno na omrežje vrste <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Naprava uporabi omrežje vrste <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, ko omrežje vrste <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nima dostopa do interneta. Prenos podatkov se lahko zaračuna posebej."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Naprava uporabi omrežje vrste <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, ko omrežje vrste <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nima dostopa do interneta. Prenos podatkov se lahko zaračuna."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Preklopljeno z omrežja vrste <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na omrežje vrste <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"prenos podatkov v mobilnem omrežju"</item>
@@ -1174,7 +1177,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"neznana vrsta omrežja"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Z omrežjem Wi-Fi se ni mogoče povezati"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima slabo internetno povezavo."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ima slabo internetno povezavo."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ali dovolite vzpostavitev povezave?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacija %1$s želi vzpostaviti povezavo z omrežjem Wi-Fi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikacija"</string>
@@ -1676,7 +1679,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. službeni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. službeni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Če želite odpeti ta zaslon, se hkrati dotaknite gumbov za nazaj in za pregled ter ju pridržite."</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Te aplikacije ni mogoče odpeti"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Zaslon je pripet"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Zaslon je odpet"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Zahtevaj PIN pred odpenjanjem"</string>
@@ -1685,7 +1687,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Namestil skrbnik"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Posodobil skrbnik"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Izbrisal skrbnik"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Varčevanje z energijo akumulatorja podaljša čas njegovega delovanja tako, da zmanjša zmogljivost delovanja naprave in omeji vibriranje, lokacijske storitve ter prenos večine podatkov v ozadju. Aplikacije za e-pošto, sporočanje in drugo, ki uporabljajo sinhroniziranje, se morda ne posodabljajo, razen če jih odprete.\n\nVarčevanje z energijo akumulatorja se samodejno izklopi med polnjenjem akumulatorja naprave."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Varčevanje z energijo akumulatorja podaljša čas njegovega delovanja tako, da zmanjša zmogljivost delovanja naprave in omeji vibriranje, lokacijske storitve ter prenos večine podatkov v ozadju. Aplikacije za e-pošto, sporočanje in drugo, ki uporabljajo sinhroniziranje, se morda ne posodabljajo, razen če jih odprete.\n\nVarčevanje z energijo akumulatorja se samodejno izklopi med polnjenjem akumulatorja naprave."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Zaradi zmanjševanja prenesene količine podatkov varčevanje s podatki nekaterim aplikacijam preprečuje, da bi v ozadju pošiljale ali prejemale podatke. Aplikacija, ki jo trenutno uporabljate, lahko prenaša podatke, vendar to morda počne manj pogosto. To na primer pomeni, da se slike ne prikažejo, dokler se jih ne dotaknete."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Vklop varčevanja s podatki?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Vklop"</string>
@@ -1852,14 +1854,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Preskus sporočil v sili"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Odgovor"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"Kartica SIM ne dovoljuje glasovnih klicev"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"Kartica SIM ne omogoča opravljanja glasovnih klicev"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"Kartica SIM ne dovoljuje glasovnih klicev"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefon ne dovoljuje glasovnih klicev"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Pojavno okno"</string>
<string name="slice_more_content" msgid="8504342889413274608">"in še <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Za to bližnjico potrebujete najnovejšo aplikacijo"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 1682557..8bf34dd 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Nuk ka shërbim zanor/urgjence"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Përkohësisht nuk ofrohet nga rrjeti celular në vendndodhjen tënde"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Rrjeti i paarritshëm"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Për të përmirësuar marrjen e sinjalit, provo të ndryshosh llojin e zgjedhur te Cilësimet > Rrjeti dhe interneti > Lloji i preferuar i rrjetit."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Për të përmirësuar marrjen e sinjalit, provo të ndryshosh llojin e zgjedhur te Cilësimet > Rrjeti dhe interneti > Rrjetet celulare > Lloji i preferuar i rrjetit."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Telefonata me Wi‑Fi është aktive"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Telefonatat e urgjencës kërkojnë një rrjet celular."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Sinjalizimet"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktivizoje sërish këtë te \"Cilësimet e sistemit\" > \"Aplikacionet\" > \"Të shkarkuara\"."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk mbështet cilësimin aktual të madhësisë së ekranit dhe mund të shfaqë sjellje të papritura."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Shfaq gjithmonë"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> është ndërtuar për një version të papërputhshëm të sistemit operativ Android dhe mund të shfaqë sjellje të papritura. Mund të ofrohet një version i përditësuar i aplikacionit."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Shfaq gjithnjë"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Kliko për përditësim"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacioni <xliff:g id="APPLICATION">%1$s</xliff:g> (procesi <xliff:g id="PROCESS">%2$s</xliff:g>) ka shkelur politikën e tij të vetë-imponuar \"Modaliteti i ashpër\" (StrictMode)."</string>
<string name="smv_process" msgid="5120397012047462446">"Procesi <xliff:g id="PROCESS">%1$s</xliff:g> ka shkelur politikën e tij të vetë-imponuar \"Modaliteti i rreptë\" (StrictMode)"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"\"Androidi\" po përditësohet…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Identifikohu në rrjet"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nuk ka qasje në internet"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi nuk ka qasje në internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Trokit për opsionet"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Kaloi te <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Pajisja përdor <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kur <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nuk ka qasje në internet. Mund të zbatohen tarifa."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Pajisja përdor <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kur <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nuk ka qasje në internet. Mund të zbatohen tarifa."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Kaloi nga <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> te <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"të dhënat celulare"</item>
@@ -1130,7 +1133,8 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"një lloj rrjeti i panjohur"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nuk mund të lidhej me Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ka një lidhje të dobët interneti."</string>
+ <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+ <skip />
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Të lejohet lidhja?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacioni %1$s do të lidhet me rrjetin Wi-Fi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Një aplikacion"</string>
@@ -1626,7 +1630,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> i dytë i punës"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> i tretë i punës"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Për të hequr gozhdimin e ekranit, prek dhe mbaj butonat \"Prapa\" dhe \"Përmbledhja\"."</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Këtij aplikacioni nuk mund t\'i hiqet gozhdimi"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Ekrani u gozhdua"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Ekrani u hoq nga gozhdimi"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Zhgozhdimi kërkon PIN-in"</string>
@@ -1635,7 +1638,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Instaluar nga administratori"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Përditësuar nga administratori"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Fshirë nga administratori"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Për të përmirësuar jetëgjatësinë e baterisë, opsioni i kursimit të baterisë ul rendimentin e pajisjes tënde si dhe kufizon dridhjet dhe shumicën e të dhënave në sfond. Email-i, mesazhet dhe aplikacionet e tjera që sinkronizohen automatikisht mund të mos përditësohen pa i hapur.\n\nKursimi i baterisë çaktivizohet automatikisht kur pajisja vihet në ngarkim."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Për të përmirësuar jetëgjatësinë e baterisë, \"Kursyesi i baterisë\" ul rendimentin e pajisjes sate si dhe kufizon dridhjet, shërbimet e vendndodhjes dhe shumicën e të dhënave në sfond. Email-i, mesazhet dhe aplikacionet e tjera që mbështeten te sinkronizimi mund të mos përditësohen nëse nuk i hap.\n\n\"Kursyesi i baterisë\" çaktivizohet automatikisht kur pajisja është në ngarkim."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Për të ndihmuar në reduktimin e përdorimit të të dhënave, \"Kursyesi i të dhënave\" pengon që disa aplikacione të dërgojnë apo të marrin të dhëna në sfond. Një aplikacion që po përdor aktualisht mund të ketë qasje te të dhënat, por këtë mund ta bëjë më rrallë. Kjo mund të nënkuptojë, për shembull, se imazhet nuk shfaqen kur troket mbi to."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Të aktivizohet \"Kursyesi i të dhënave\"?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Aktivizo"</string>
@@ -1782,14 +1785,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Testim për mesazhet e urgjencës"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Përgjigju"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"Karta SIM nuk lejohet për zërin"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"Karta SIM nuk është e përgatitur për zërin"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"Karta SIM nuk lejohet për zërin"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefoni nuk lejohet për zërin"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Dritare kërcyese"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Kjo shkurtore kërkon aplikacionin më të fundit"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index b6de548..7c6460be 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -80,7 +80,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Нема гласовне услуге/услуге за хитне позиве"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Привремено је онемогућено на мобилној мрежи на вашој локацији"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Повезивање са мрежом није успело"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Да бисте побољшали пријем, пробајте да промените изабрани тип у одељку Подешавања > Мрежа и интернет > Мобилне мреже > Жељени тип мреже."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Да бисте побољшали пријем, пробајте да промените изабрани тип у одељку Подешавања > Мрежа и интернет > Мобилне мреже > Жељени тип мреже."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi позивање је активно"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Хитни позиви захтевају мобилну мрежу."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Обавештења"</string>
@@ -1071,6 +1071,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Поново омогућите у менију Системска подешавања > Апликације > Преузето."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не подржава тренутно подешавање величине приказа и може да се понаша неочекивано."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Увек приказуј"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је направљена за некомпатибилну верзију Android ОС-а и може да се понаша на неочекиван начин. Можда је доступна ажурирана верзија апликације."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Увек прикажи"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Потражи ажурирање"</string>
<string name="smv_application" msgid="3307209192155442829">"Апликација <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) је прекршила самонаметнуте StrictMode смернице."</string>
<string name="smv_process" msgid="5120397012047462446">"Процес <xliff:g id="PROCESS">%1$s</xliff:g> је прекршио самонаметнуте StrictMode смернице."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android се надограђује…"</string>
@@ -1138,10 +1141,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Пријавите се на мрежу"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi нема приступ интернету"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi нема приступ интернету"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Додирните за опције"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Прешли сте на тип мреже <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Уређај користи тип мреже <xliff:g id="NEW_NETWORK">%1$s</xliff:g> када тип мреже <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема приступ интернету. Можда ће се наплаћивати трошкови."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Уређај користи тип мреже <xliff:g id="NEW_NETWORK">%1$s</xliff:g> када тип мреже <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема приступ интернету. Можда ће се наплаћивати трошкови."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Прешли сте са типа мреже <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на тип мреже <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"мобилни подаци"</item>
@@ -1152,7 +1155,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"непознат тип мреже"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Није могуће повезати са Wi-Fi мрежом"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има лошу интернет везу."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" има лошу интернет везу."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Желите ли да дозволите повезивање?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Апликација %1$s жели да се повеже на Wi-Fi мрежу %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Апликација"</string>
@@ -1659,7 +1662,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Инсталирао је администратор"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Ажурирао је администратор"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Избрисао је администратор"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Да би продужила време трајања батерије, уштеда батерије смањује перформансе уређаја и ограничава вибрацију, услуге локације и већину позадинских података. Имејл, размена порука и друге апликације које се ослањају на синхронизацију неће се ажурирати док их не отворите.\n\nУштеда батерије се аутоматски искључује када се уређај пуни."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Да би продужила трајање батерије, Уштеда батерије смањује перформансе уређаја и ограничава вибрацију, услуге локације и већину позадинских података. Имејл, размена порука и друге апликације које се ослањају на синхронизацију се неће ажурирати ако их не отворите.\n\nУштеда батерије се аутоматски искључује када се уређај пуни."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Да би се смањила потрошња података, Уштеда података спречава неке апликације да шаљу или примају податке у позадини. Апликација коју тренутно користите може да приступа подацима, али ће то чинити ређе. На пример, слике се неће приказивати док их не додирнете."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Укључити Уштеду података?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Укључи"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index cd5ec95..b894c83 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Tjänster för röst- och nödsamtal har blockerats"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Detta erbjuds för tillfället inte på mobilnätverket där du befinner dig"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Det går inte att nå nätverket"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Testa om du får bättre mottagning genom att ändra till en annan typ under Inställningar > Nätverk och internet > Mobila nätverk > Önskad nätverkstyp."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Testa om du får bättre mottagning genom att ändra till en annan typ under Inställningar > Nätverk och internet > Mobila nätverk > Önskad nätverkstyp."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi-Fi-samtal är aktiverat"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Mobilnätverk krävs för att ringa nödsamtal."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Aviseringar"</string>
@@ -431,7 +431,7 @@
<string name="permdesc_setTimeZone" product="tv" msgid="888864653946175955">"Tillåter att appen ändrar tidszonen på TV:n."</string>
<string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Tillåter att appen ändrar mobilens tidszon."</string>
<string name="permlab_getAccounts" msgid="1086795467760122114">"hitta konton på enheten"</string>
- <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Tillåter att appen hämtar en lista över alla kända konton på surfplattan. Detta kan inkludera konton som har skapats av appar som du har installerat."</string>
+ <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Tillåter att appen laddar ned en lista över alla kända konton på surfplattan. Detta kan inkludera konton som har skapats av appar som du har installerat."</string>
<string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"Tillåter att appen hämtar listan med konton som TV:n kan identifiera. Den kan innehålla konton som skapats av appar som du har installerat."</string>
<string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Tillåter att appen hämtar en lista över alla kända konton på mobilen. Detta kan inkludera konton som har skapats av appar som du har installerat."</string>
<string name="permlab_accessNetworkState" msgid="4951027964348974773">"visa nätverksanslutningar"</string>
@@ -452,7 +452,7 @@
<string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Tillåter att appen tar emot paket som skickats med multicast-adress till alla enheter i ett Wi-Fi-nätverk och inte bara till den här mobilen. Detta drar mer batteri än när multicastläget inte används."</string>
<string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"få åtkomst till Bluetooth-inställningar"</string>
<string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Tillåter att appen konfigurerar den lokala Bluetooth-surfplattan samt upptäcker och parkopplar den med fjärranslutna enheter."</string>
- <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Tillåter att appen konfigurerar den lokala Bluetooth-TV:n och identifierar och kopplar den till fjärrenheter."</string>
+ <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Tillåter att appen konfigurerar den lokala Bluetooth-TV:n och identifierar och parkopplar den till fjärrenheter."</string>
<string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Tillåter att appen konfigurerar den lokala Bluetooth-mobilen samt upptäcker och parkopplar den med fjärranslutna enheter."</string>
<string name="permlab_accessWimaxState" msgid="4195907010610205703">"ansluta till och koppla från WiMAX"</string>
<string name="permdesc_accessWimaxState" msgid="6360102877261978887">"Tillåter att appen avgör om WiMAX är aktiverat och kommer åt information om eventuella anslutna WiMAX-nätverk."</string>
@@ -460,7 +460,7 @@
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Tillåter att appen ansluter surfplattan till eller kopplar från WiMAX-nätverk."</string>
<string name="permdesc_changeWimaxState" product="tv" msgid="6022307083934827718">"Tillåter att appen ansluter TV:n till och kopplar från TV:n från WiMAX-nätverk."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Tillåter att appen ansluter mobilen till eller kopplar från WiMAX-nätverk."</string>
- <string name="permlab_bluetooth" msgid="6127769336339276828">"koppla till Bluetooth-enheter"</string>
+ <string name="permlab_bluetooth" msgid="6127769336339276828">"parkoppla till Bluetooth-enheter"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Tillåter att appen kommer åt pekdatorns Bluetooth-konfiguration och upprättar och godkänner anslutningar till parkopplade enheter."</string>
<string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"Tillåter att appen visar konfigurationen av Bluetooth på TV:n och godkänner alla anslutningar till kopplade enheter."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Tillåter att appen kommer åt mobilens Bluetooth-konfiguration och upprättar och godkänner anslutningar till parkopplade enheter."</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktivera detta igen i Systeminställningar > Appar > Hämtat."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inte stöd för den nuvarande inställningen för skärmstorlek och kanske inte fungerar som förväntat."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Visa alltid"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> skapades för en inkompatibel version av operativsystemet Android och kanske inte fungerar som förväntat. En uppdaterad version av appen kan vara tillgänglig."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Visa alltid"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Sök efter uppdateringar"</string>
<string name="smv_application" msgid="3307209192155442829">"Appen <xliff:g id="APPLICATION">%1$s</xliff:g> (processen <xliff:g id="PROCESS">%2$s</xliff:g>) har brutit mot sin egen StrictMode-policy."</string>
<string name="smv_process" msgid="5120397012047462446">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> har brutit mot sin egen StrictMode-policy."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android uppgraderas ..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Logga in på nätverket"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-nätverket är inte anslutet till internet"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi-nätverket är inte anslutet till internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tryck för alternativ"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Byte av nätverk till <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> används på enheten när det inte finns internetåtkomst via <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Avgifter kan tillkomma."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> används på enheten när det inte finns internetåtkomst via <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Avgifter kan tillkomma."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Byte av nätverk från <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> till <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobildata"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"en okänd nätverkstyp"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Det gick inte att ansluta till Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dålig Internetanslutning."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" har en dålig Internetanslutning."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Tillåt anslutning?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Appen %1$s vill ansluta till Wi-Fi-nätverket %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"En app"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Andra <xliff:g id="LABEL">%1$s</xliff:g> för jobbet"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Tredje <xliff:g id="LABEL">%1$s</xliff:g> för jobbet"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Om du vill lossa skärmen trycker du länge på knapparna Tillbaka och Översikt"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Denna app kan inte lossas"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Skärmen är fäst"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Skärmen är inte längre fäst"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Be om pinkod innan skärmen slutar fästas"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Administratören installerade paketet"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Administratören uppdaterade paketet"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Administratören raderade paketet"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"I batterisparläget reduceras enhetens prestanda så att batteriet ska räcka längre och vibration, platstjänster samt den mesta användningen av bakgrundsdata begränsas. Det kan hända att appar för e-post, sms och annat som kräver synkronisering inte uppdateras förrän du öppnar dem.\n\nBatterisparläget inaktiveras automatiskt när enheten laddas."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"I batterisparläget reduceras enhetens prestanda så att batteriet ska räcka längre. Vibration, platstjänster och den mesta användningen av bakgrundsdata begränsas. Det kan hända att appar för e-post, sms och annat som kräver synkronisering inte uppdateras förrän du öppnar dem.\n\nBatterisparläget inaktiveras automatiskt när enheten laddas."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Med databesparing kan du minska dataanvändningen genom att hindra en del appar från att skicka eller ta emot data i bakgrunden. Appar som du använder kan komma åt data, men det sker kanske inte lika ofta. Detta innebär t.ex. att bilder inte visas förrän du trycker på dem."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Aktivera Databesparing?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Aktivera"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test för nödmeddelanden"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Svara"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM-kort tillåts inte för röst"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM-kort tillhandahålls inte för röst"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM-kort tillåts inte för röst"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefon tillåts inte för röst"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"popup-fönster"</string>
<string name="slice_more_content" msgid="8504342889413274608">"<xliff:g id="NUMBER">%1$d</xliff:g> till"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Den här genvägen kräver den senaste versionen av appen"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index c866c4c..bdf304a 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Hakuna huduma ya simu za dharura au za sauti"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Kwa sasa, huduma hii haipatikani katika mtandao wa simu mahali ulipo"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Haiwezi kufikia mtandao"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Ili kupata mtandao thabiti, jaribu kubadilisha aina uliyochagua katika Mipangilio > Mtandao na Intaneti > Mitandao ya simu > Aina ya mtandao unaopendelea."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Ili kupata mtandao thabiti, jaribu kubadilisha aina uliyochagua katika Mipangilio > Mtandao na intaneti > Mtandao wa simu > Aina ya mtandao unaopendelea."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Umewasha kipengele cha kupiga simu kupitia Wi‑Fi"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Huduma ya kupiga simu za dharura inahitaji mtandao wa simu."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Arifa"</string>
@@ -1049,6 +1049,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Wezesha tena hii katika mipangilio ya Mfumo > Programu > iliyopakuliwa."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> haiwezi kutumia mipangilio ya sasa ya ukubwa wa Skrini na huenda isifanye kazi vizuri."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Onyesha kila wakati"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> imeundwa kutumiwa katika toleo lisilooana na mfumo wa uendeshaji wa Android na huenda isifanye kazi vizuri. Huenda toleo jipya la programu linapatikana."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Onyesha kila wakati"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Angalia masasisho"</string>
<string name="smv_application" msgid="3307209192155442829">"Programu <xliff:g id="APPLICATION">%1$s</xliff:g> (utaratibu <xliff:g id="PROCESS">%2$s</xliff:g>) imeenda kinyume na sera yake ya StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Shughuli ya <xliff:g id="PROCESS">%1$s</xliff:g> imeenda kinyume na kulazimisha sera yake ya StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Toleo jipya la Android linawekwa..."</string>
@@ -1114,10 +1117,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Ingia katika mtandao"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi haina muunganisho wa intaneti"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi haina muunganisho wa intaneti"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Gusa ili upate chaguo"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Sasa inatumia <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Kifaa hutumia <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wakati <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> haina Intaneti. Huenda ukalipishwa."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Kifaa hutumia <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wakati <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> haina intaneti. Huenda ukalipishwa."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Imebadilisha mtandao kutoka <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sasa inatumia <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"data ya simu"</item>
@@ -1128,7 +1131,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"aina ya mtandao isiyojulikana"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Haikuweza kuunganisha kwa Mtandao-Hewa"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ina muunganisho duni wa Mtandao."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" inao muunganisho duni wa wavuti."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ungepenga kuruhusu muunganisho?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Programu ya %1$s ingependa kuunganisha kwenye Mtandao wa Wifi wa %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Programu"</string>
@@ -1632,7 +1635,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Imesakinishwa na msimamizi wako"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Imesasishwa na msimamizi wako"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Imefutwa na msimamizi wako"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Ili kuboresha muda wa matumizi ya betri, kiokoa betri hupunguza utendaji wa kifaa chako na kupunguza mtetemo, huduma za utambuzi wa mahali na data nyingi ya chini chini. Programu za barua pepe, za kutuma ujumbe na zinginezo, zinazotegemea usawazishaji huenda zisisasishwe usipozifungua.\n\nKiokoa betri hujizima kiotomatiki wakati kifaa chako kinachaji."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Ili kuboresha muda wa matumizi ya betri, Kiokoa Betri hupunguza utendaji wa kifaa chako na kupunguza mtetemo, huduma za utambuzi wa mahali na data nyingi ya chini chini. Huenda haitasasisha programu za barua pepe, ujumbe na programu zinginezo zinazotegemea usawazishaji, usipozifungua.\n\nKiokoa Betri hujizima kiotomatiki wakati kifaa chako kinachaji."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Ili kusaidia kupunguza matumizi ya data, Kiokoa Data huzuia baadhi ya programu kupokea na kutuma data chini chini. Programu ambayo unatumia sasa inaweza kufikia data, lakini si kila wakati. Kwa mfano, haitaonyesha picha hadi utakapozifungua."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Ungependa Kuwasha Kiokoa Data?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Washa"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index e318851..9b77ec0 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -79,8 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"குரல்/அவசரச் சேவை இல்லை"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"தற்காலிகமாக உங்கள் இருப்பிடத்தில் மொபைல் நெட்வொர்க் வழங்கவில்லை"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"நெட்வொர்க்குடன் இணைக்க முடியவில்லை"</string>
- <!-- no translation found for NetworkPreferenceSwitchSummary (7056776609127756440) -->
- <skip />
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"இணைய இணைப்பை நன்றாகக் கிடைப்பதற்கு, அமைப்புகள் > நெட்வொர்க் & இண்டர்நெட் > மொபைல் நெட்வொர்க்குகள் > முன்னுரிமை நெட்வொர்க் வகை என்பதற்குச் சென்று, தேர்ந்தெடுத்த வகையை மாற்றவும்."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"வைஃபை அழைப்பு இயக்கத்தில் உள்ளது"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"அவசர அழைப்புகளுக்கு, மொபைல் நெட்வொர்க் தேவை."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"விழிப்பூட்டல்கள்"</string>
@@ -1052,12 +1051,10 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"சிஸ்டம் அமைப்பு > பயன்பாடுகள் > பதிவிறக்கம் என்பதில் இதை மீண்டும் இயக்கவும்."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"தற்போதைய திரை அளவு அமைப்பை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காததால், அது வழக்கத்திற்கு மாறாகச் செயல்படக்கூடும்."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"எப்போதும் காட்டு"</string>
- <!-- no translation found for unsupported_compile_sdk_message (5030433583092006591) -->
+ <!-- no translation found for unsupported_compile_sdk_message (4253168368781441759) -->
<skip />
- <!-- no translation found for unsupported_compile_sdk_show (2681877855260970231) -->
- <skip />
- <!-- no translation found for unsupported_compile_sdk_check_update (3312723623323216101) -->
- <skip />
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"எப்போதும் காட்டு"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"புதுப்பிப்பு உள்ளதா எனப் பார்"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> பயன்பாடு (செயல்முறை <xliff:g id="PROCESS">%2$s</xliff:g>), தனது சுய-செயலாக்க StrictMode கொள்கையை மீறியது."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> செயல்முறை, தனது சுய-செயலாக்க StrictMode கொள்கையை மீறியது."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android மேம்படுத்தப்படுகிறது…"</string>
@@ -1123,12 +1120,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"நெட்வொர்க்கில் உள்நுழையவும்"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <!-- no translation found for wifi_no_internet (8938267198124654938) -->
- <skip />
+ <string name="wifi_no_internet" msgid="8938267198124654938">"வைஃபையில் இண்டர்நெட் அணுகல் இல்லை"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"விருப்பங்களுக்கு, தட்டவும்"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
- <!-- no translation found for network_switch_metered_detail (775163331794506615) -->
- <skip />
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> நெட்வொர்க்கில் இண்டர்நெட் அணுகல் இல்லாததால், சாதனமானது <xliff:g id="NEW_NETWORK">%1$s</xliff:g> நெட்வொர்க்கைப் பயன்படுத்துகிறது. கட்டணங்கள் விதிக்கப்படலாம்."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> இலிருந்து <xliff:g id="NEW_NETWORK">%2$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"மொபைல் டேட்டா"</item>
@@ -1644,7 +1639,8 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"உங்கள் நிர்வாகி நிறுவியுள்ளார்"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"உங்கள் நிர்வாகி புதுப்பித்துள்ளார்"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"உங்கள் நிர்வாகி நீக்கியுள்ளார்"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"பேட்டரி ஆயுளை நீட்டிக்க, பேட்டரி சேமிப்பான் உங்கள் சாதனத்தின் செயல்திறனைக் குறைத்து, அதிர்வு, இடச் சேவைகள் மற்றும் பெரும்பாலான பின்புலத் தரவு போன்றவற்றைக் கட்டுப்படுத்துகிறது. ஒத்திசைவைச் சார்ந்துள்ள மின்னஞ்சல், செய்திச் சேவை மற்றும் பிற பயன்பாடுகளைத் திறக்கும்வரை, அவற்றில் புதிய தகவலைப் பார்க்க முடியாமல் போகலாம்.\n\nஉங்கள் ஃபோன் சார்ஜ் செய்யப்படும்போது, பேட்டரி சேமிப்பான் தானாகவே அணைக்கப்படும்."</string>
+ <!-- no translation found for battery_saver_description (5394663545060026162) -->
+ <skip />
<string name="data_saver_description" msgid="6015391409098303235">"டேட்டா பயன்பாட்டைக் குறைப்பதற்கு உதவ, பின்புலத்தில் டேட்டாவை அனுப்புவது அல்லது பெறுவதிலிருந்து சில பயன்பாடுகளை டேட்டா சேமிப்பான் தடுக்கும். தற்போது பயன்படுத்தும் பயன்பாடானது எப்போதாவது டேட்டாவை அணுகலாம். எடுத்துக்காட்டாக, படங்களை நீங்கள் தட்டும் வரை அவை காட்டப்படாது."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"டேட்டா சேமிப்பானை இயக்கவா?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"இயக்கு"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 8ae8401f..8658ae9 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"వాయిస్/అత్యవసర సేవ లేదు"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"మీ స్థానంలో మొబైల్ నెట్వర్క్ ద్వారా తాత్కాలికంగా అందించబడదు"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"నెట్వర్క్ను చేరుకోలేరు"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"స్వీకరణను మెరుగుపరచాలంటే, సెట్టింగ్లు > నెట్వర్క్ & ఇంటర్నెట్ > మొబైల్ నెట్వర్క్లు > ప్రాధాన్య నెట్వర్క్ రకంలో మీరు ఎంచుకున్న రకాన్ని మార్చి ప్రయత్నించండి."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"స్వీకరణను మెరుగుపరచాలంటే, సెట్టింగ్లు > నెట్వర్క్ & ఇంటర్నెట్ > మొబైల్ నెట్వర్క్లు > ప్రాధాన్య నెట్వర్క్ రకంలో మీరు ఎంచుకున్న రకాన్ని మార్చి ప్రయత్నించండి."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi-Fi కాలింగ్ సక్రియంగా ఉంది"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"అత్యవసర కాల్లకు మొబైల్ నెట్వర్క్ అవసరమవుతుంది."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"హెచ్చరికలు"</string>
@@ -1051,6 +1051,10 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"సిస్టమ్ సెట్టింగ్లు > అనువర్తనాలు > డౌన్లోడ్ చేసినవిలో దీన్ని పునఃప్రారంభించండి."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ప్రస్తుత ప్రదర్శన పరిమాణ సెట్టింగ్కు మద్దతు ఇవ్వదు, దీని వలన ఊహించని సమస్యలు తలెత్తవచ్చు."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ఎల్లప్పుడూ చూపు"</string>
+ <!-- no translation found for unsupported_compile_sdk_message (4253168368781441759) -->
+ <skip />
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"ఎల్లప్పుడూ చూపు"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"అప్డేట్ కోసం తనిఖీ చేయి"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> యాప్ (<xliff:g id="PROCESS">%2$s</xliff:g> ప్రాసెస్) అది స్వయంగా అమలు చేసే ఖచ్చితమైన మోడ్ విధానాన్ని ఉల్లంఘించింది."</string>
<string name="smv_process" msgid="5120397012047462446">"ప్రక్రియ <xliff:g id="PROCESS">%1$s</xliff:g> అది స్వయంగా అమలు చేసే ఖచ్చితమైన మోడ్ విధానాన్ని ఉల్లంఘించింది."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android అప్గ్రేడ్ అవుతోంది…"</string>
@@ -1116,10 +1120,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"నెట్వర్క్కి సైన్ ఇన్ చేయండి"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fiకి ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fiకి ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ఎంపికల కోసం నొక్కండి"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>కి మార్చబడింది"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"పరికరం <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>కి ఇంటర్నెట్ యాక్సెస్ లేనప్పుడు <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ని ఉపయోగిస్తుంది. ఛార్జీలు వర్తించవచ్చు."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"పరికరం <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>కి ఇంటర్నెట్ యాక్సెస్ లేనప్పుడు <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ని ఉపయోగిస్తుంది. ఛార్జీలు వర్తించవచ్చు."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> నుండి <xliff:g id="NEW_NETWORK">%2$s</xliff:g>కి మార్చబడింది"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"మొబైల్ డేటా"</item>
@@ -1130,7 +1134,8 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"తెలియని నెట్వర్క్ రకం"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fiకి కనెక్ట్ చేయడం సాధ్యపడలేదు"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" బలహీన ఇంటర్నెట్ కనెక్షన్ను కలిగి ఉంది."</string>
+ <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+ <skip />
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"కనెక్షన్ని అనుమతించాలా?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s యాప్ %2$s Wifi నెట్వర్క్కు కనెక్ట్ చేయాలనుకుంటోంది"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"ఒక యాప్"</string>
@@ -1634,7 +1639,8 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"మీ నిర్వాహకులు ఇన్స్టాల్ చేసారు"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"మీ నిర్వాహకులు నవీకరించారు"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"మీ నిర్వాహకులు తొలగించారు"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"బ్యాటరీ జీవితకాలాన్ని మెరుగుపరచడంలో సహాయపడటానికి, బ్యాటరీ సేవర్ మీ పరికరం పనితీరును తగ్గిస్తుంది మరియు వైబ్రేషన్ను, స్థాన సేవలను మరియు అత్యధిక నేపథ్య డేటాను పరిమితం చేస్తుంది. ఇమెయిల్, మెసేజింగ్ మరియు సమకాలీకరణపై ఆధారపడే ఇతర యాప్లు మీరు వాటిని తెరిస్తే మినహా అప్డేట్ చేయబడవు.\n\nమీ పరికరం ఛార్జ్ అవుతున్నప్పుడు బ్యాటరీ సేవర్ స్వయంచాలకంగా ఆఫ్ అవుతుంది."</string>
+ <!-- no translation found for battery_saver_description (5394663545060026162) -->
+ <skip />
<string name="data_saver_description" msgid="6015391409098303235">"డేటా వినియోగాన్ని తగ్గించడంలో సహాయకరంగా ఉండటానికి, డేటా సేవర్ కొన్ని యాప్లను నేపథ్యంలో డేటాను పంపకుండా లేదా స్వీకరించకుండా నిరోధిస్తుంది. మీరు ప్రస్తుతం ఉపయోగిస్తున్న యాప్ డేటాను యాక్సెస్ చేయగలదు కానీ అలా అరుదుగా చేయవచ్చు. అంటే, ఉదాహరణకు, మీరు ఆ చిత్రాలను నొక్కే వరకు అవి ప్రదర్శించబడవు."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"డేటా సేవర్ను ఆన్ చేయాలా?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ఆన్ చేయి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 1ccb751..026611f 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"ไม่มีบริการเสียง/บริการฉุกเฉิน"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"งดให้บริการชั่วคราวโดยเครือข่ายมือถือในตำแหน่งของคุณ"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"เข้าถึงเครือข่ายไม่ได้"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"ลองเปลี่ยนประเภทที่เลือกใน \"การตั้งค่า\" > \"เครือข่ายและอินเทอร์เน็ต\" > \"เครือข่ายมือถือ\" > \"ประเภทเครือข่ายที่ต้องการ\" เพื่อให้การรับสัญญาณดีขึ้น"</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"ลองเปลี่ยนประเภทที่เลือกใน \"การตั้งค่า\" > \"เครือข่ายและอินเทอร์เน็ต\" > \"เครือข่ายมือถือ\" > \"ประเภทเครือข่ายที่ต้องการ\" เพื่อให้การรับสัญญาณดีขึ้น"</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"กำลังใช้งานการโทรผ่าน Wi-Fi"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"หมายเลขฉุกเฉินต้องใช้เครือข่ายมือถือ"</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"การแจ้งเตือน"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"เปิดใช้งานอีกครั้งในการตั้งค่าระบบ > แอปพลิเคชัน > ดาวน์โหลด"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่สนับสนุนการตั้งค่าขนาดการแสดงผลปัจจุบันและอาจแสดงผลผิดปกติ"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"แสดงเสมอ"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> สร้างมาสำหรับระบบปฏิบัติการ Android เวอร์ชันที่ใช้ร่วมกันไม่ได้ และอาจแสดงผลผิดปกติ ทั้งนี้ แอปเวอร์ชันอัปเดตอาจพร้อมใช้งานแล้ว"</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"แสดงเสมอ"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"ตรวจสอบอัปเดต"</string>
<string name="smv_application" msgid="3307209192155442829">"แอปพลิเคชัน <xliff:g id="APPLICATION">%1$s</xliff:g> (กระบวนการ <xliff:g id="PROCESS">%2$s</xliff:g>) ละเมิดนโยบาย StrictMode ที่บังคับใช้ด้วยตัวเอง"</string>
<string name="smv_process" msgid="5120397012047462446">"กระบวนการ <xliff:g id="PROCESS">%1$s</xliff:g> ละเมิดนโยบาย StrictMode ที่บังคับใช้ด้วยตัวเอง"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"กำลังอัปเกรด Android ..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"ลงชื่อเข้าใช้เครือข่าย"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi เชื่อมต่ออินเทอร์เน็ตไม่ได้"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi เชื่อมต่ออินเทอร์เน็ตไม่ได้"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"แตะเพื่อดูตัวเลือก"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"เปลี่ยนเป็น <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"อุปกรณ์จะใช้ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> เมื่อ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ไม่สามารถเข้าถึงอินเทอร์เน็ต อาจมีค่าบริการ"</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"อุปกรณ์จะใช้ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> เมื่อ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> เข้าถึงอินเทอร์เน็ตไม่ได้ โดยอาจมีค่าบริการ"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"เปลี่ยนจาก <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> เป็น <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"อินเทอร์เน็ตมือถือ"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ประเภทเครือข่ายที่ไม่รู้จัก"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ไม่สามารถเชื่อมต่อ WiFi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" มีสัญญาณอินเทอร์เน็ตไม่ดี"</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" มีสัญญาณอินเทอร์เน็ตไม่ดี"</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"อนุญาตการเชื่อมต่อใช่ไหม"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"แอปพลิเคชัน %1$s ต้องการเชื่อมต่อเครือข่าย Wi-Fi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"แอปพลิเคชัน"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> งานที่ 2"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> งานที่ 3"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"หากต้องการเลิกตรึงหน้าจอนี้ ให้แตะปุ่ม \"กลับ\" และ \"ภาพรวม\" ค้างไว้"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"เลิกตรึงแอปนี้ไม่ได้"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"ตรึงหน้าจอแล้ว"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"เลิกตรึงหน้าจอแล้ว"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ขอ PIN ก่อนเลิกตรึง"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"ติดตั้งโดยผู้ดูแลระบบ"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"อัปเดตโดยผู้ดูแลระบบ"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"ลบโดยผู้ดูแลระบบ"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"เพื่อช่วยยืดอายุการใช้งานแบตเตอรี่ โหมดประหยัดแบตเตอรี่จะลดการทำงานของอุปกรณ์และจำกัดการสั่น บริการตำแหน่ง และข้อมูลแบ็กกราวด์ส่วนใหญ่ สำหรับอีเมล การรับส่งข้อความ และแอปอื่นๆ ที่ใช้การซิงค์จะไม่อัปเดตหากคุณไม่เปิดขึ้นมา\n\nโหมดประหยัดแบตเตอรี่จะปิดโดยอัตโนมัติขณะชาร์จอุปกรณ์"</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"เพื่อช่วยปรับปรุงอายุการใช้งานแบตเตอรี่ โหมดประหยัดแบตเตอรี่จะลดการทำงานของอุปกรณ์และจำกัดการสั่น บริการตำแหน่ง และข้อมูลแบ็กกราวด์ส่วนใหญ่ สำหรับอีเมล การรับส่งข้อความ และแอปอื่นๆ ที่ใช้การซิงค์จะไม่อัปเดตหากคุณไม่เปิดขึ้นมา\n\nโหมดประหยัดแบตเตอรี่จะปิดโดยอัตโนมัติขณะชาร์จอุปกรณ์"</string>
<string name="data_saver_description" msgid="6015391409098303235">"เพื่อช่วยลดปริมาณการใช้อินเทอร์เน็ต โปรแกรมประหยัดอินเทอร์เน็ตจะช่วยป้องกันไม่ให้บางแอปส่งหรือรับข้อมูลเครือข่ายมือถือในการทำงานเบื้องหลัง แอปที่คุณกำลังใช้งานสามารถเข้าถึงข้อมูลเครือข่ายมือถือได้ แต่อาจไม่บ่อยเท่าเดิม ตัวอย่างเช่น ภาพต่างๆ จะไม่แสดงจนกว่าคุณจะแตะที่ภาพเหล่านั้น"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"เปิดการประหยัดอินเทอร์เน็ตไหม"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"เปิด"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"การทดสอบข้อความกรณีฉุกเฉิน"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"ตอบ"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"ไม่อนุญาตให้ใช้ซิมสำหรับเสียง"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"ไม่มีการจัดสรรซิมสำหรับเสียง"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"ไม่อนุญาตให้ใช้ซิมสำหรับเสียง"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"ไม่อนุญาตให้ใช้โทรศัพท์สำหรับเสียง"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"หน้าต่างป๊อปอัป"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"ทางลัดนี้ต้องใช้แอปล่าสุด"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 5a9d118..7f4063a 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Walang serbisyo para sa voice/emergency"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Pansamantalang hindi inaalok ng mobile network sa iyong lokasyon"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Hindi maabot ang network"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Upang mapahusay ang reception, subukang baguhin ang uring napili sa Mga Setting > Network at Internet > Mga mobile network > Gustong uri ng network."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Upang mapahusay ang reception, subukang baguhin ang uring napili sa Mga Setting > Network at internet > Mga mobile network > Gustong uri ng network."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Aktibo ang pagtawag sa pamamagitan ng Wi‑Fi"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Nangangailangan ng mobile network ang mga emergency na tawag."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Mga Alerto"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Muling paganahin ito sa mga setting ng System > Apps > Na-download."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Hindi sinusuportahan ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang kasalukuyang setting ng laki ng Display at maaaring may mangyaring hindi inaasahan."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Palaging ipakita"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Binuo ang <xliff:g id="APP_NAME">%1$s</xliff:g> para sa hindi tugmang bersyon ng Android OS at maaaring may gawin itong hindi inaasahan. Maaaring may available na updated na bersyon ng app."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Palaging ipakita"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Tingnan kung may update"</string>
<string name="smv_application" msgid="3307209192155442829">"Ang app na <xliff:g id="APPLICATION">%1$s</xliff:g> (prosesong <xliff:g id="PROCESS">%2$s</xliff:g>) ay lumabag sa sarili nitong ipinapatupad na patakarang StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Ang prosesong <xliff:g id="PROCESS">%1$s</xliff:g> ay lumabag sa sarili nitong ipinapatupad na patakarang StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Nag-a-upgrade ang Android…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Mag-sign in sa network"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Walang access sa Internet ang Wi-Fi"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Walang access sa internet ang Wi-Fi"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"I-tap para sa mga opsyon"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Lumipat sa <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Ginagamit ng device ang <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kapag walang access sa Internet ang <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Maaaring may mga malapat na singilin."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Ginagamit ng device ang <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kapag walang access sa internet ang <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Maaaring may mga malapat na singilin."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Lumipat sa <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mula sa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobile data"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"isang hindi kilalang uri ng network"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Hindi makakonekta sa Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ay mayroong mahinang koneksyon sa Internet."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ay mayroong mahinang koneksyon sa internet."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Payagan ang kuneksyon?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Gustong kumonekta ng application na %1$s sa Wifi Network na %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Isang application"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Pangalawang <xliff:g id="LABEL">%1$s</xliff:g> sa Trabaho"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Pangatlong <xliff:g id="LABEL">%1$s</xliff:g> sa Trabaho"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Upang i-unpin ang screen na ito, pindutin nang matagal ang mga button na Bumalik at Pangkalahatang-ideya"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Hindi ma-unpin ang app na ito"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Naka-pin ang screen"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Naka-unpin ang screen"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Humingi ng PIN bago mag-unpin"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Na-install ng iyong admin"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Na-update ng iyong admin"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Na-delete ng iyong admin"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Upang matulungang pagbutihin ang tagal ng baterya, binabawasan ng pangtipid ng baterya ang performance ng iyong device at nililimitahan ang pag-vibrate, mga serbisyo ng lokasyon at karamihan sa data ng background. Maaaring hindi mag-update ang email, pagmemensahe at iba pang mga app na umaasa sa pagsi-sync maliban kung buksan mo ang mga iyon.\n\nAwtomatikong nag-o-off ang pangtipid ng baterya kapag nagcha-charge ang iyong device."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Upang matulungang mapatagal ang baterya, binabawasan ng Pangtipid sa Baterya ang performance ng iyong device at nililimitahan nito ang pag-vibrate, mga serbisyo ng lokasyon, at halos lahat ng background na data. Hindi maaaring ma-update ang email, messaging, at iba pang app na umaasa sa pag-sync hangga\'t hindi mo binubuksan ang mga ito.\n\nAwtomatikong nag-o-off ang Pangtipid sa Baterya kapag naka-charge ang iyong device."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Upang makatulong na mabawasan ang paggamit ng data, pinipigilan ng Data Saver ang ilang app na magpadala o makatanggap ng data sa background. Maaaring mag-access ng data ang isang app na ginagamit mo sa kasalukuyan, ngunit mas bihira na nito magagawa iyon. Halimbawa, maaaring hindi lumabas ang mga larawan hangga\'t hindi mo nata-tap ang mga ito."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"I-on ang Data Saver?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"I-on"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Pagsubok sa mga mensaheng pang-emergency"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Tumugon"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"Hindi pinapayagan ang SIM para sa boses"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"Hindi naka-provision ang SIM para sa boses"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"Hindi pinapayagan ang SIM para sa boses"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Hindi pinapayagan ang telepono para sa boses"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Window ng Popup"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Kinakailangan ng shortcut na ito ang pinakabagong app"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 8b77850..47792b4 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Ses/acil durum hizmeti yok"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Bulunduğunuz yerdeki mobil ağ tarafından geçici olarak sunulmuyor"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Ağa erişilemiyor"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Sinyal gücünü iyileştirmek için Ayarlar > Ağ ve İnternet > Mobil ağlar > Tercih edilen ağ türü bölümünde seçili türü değiştirmeyi deneyin."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Sinyal gücünü iyileştirmek için Ayarlar > Ağ ve İnternet > Mobil ağlar > Tercih edilen ağ türü bölümünde seçili türü değiştirmeyi deneyin."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Kablosuz çağrı etkin"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Acil durum çağrıları için mobil ağ gereklidir."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Uyarılar"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Bunu Sistem ayarları > Uygulamalar > İndirilenler bölümünden yeniden etkinleştirin."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> geçerli Ekran boyutu ayarını desteklemiyor ve beklenmedik bir şekilde davranabilir."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Her zaman göster"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulaması Android OS\'un uyumlu olmayan önceki bir sürümü için geliştirilmiştir ve beklenmedik şekilde davranabilir. Uygulamanın güncellenmiş bir sürümü mevcut olabilir."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Her zaman göster"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Güncellemeleri denetle"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işlemi) kendiliğinden uyguladığı StrictMode politikasını ihlal etti."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> işlemi kendiliğinden uyguladığı StrictMode politikasını ihlal etti."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android yeni sürüme geçiriliyor..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Ağda oturum açın"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Kablosuz bağlantıda İnternet erişimi yok"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Kablosuz bağlantının internet erişimi yok"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Seçenekler için dokunun"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ağına geçildi"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ağının İnternet erişimi olmadığında cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ağını kullanır. Bunun için ödeme alınabilir."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ağının internet erişimi olmadığında cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ağını kullanır. Bunun için ödeme alınabilir."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ağından <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ağına geçildi"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobil veri"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"bilinmeyen ağ türü"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kablosuz bağlantısı kurulamadı"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" İnternet bağlantısı zayıf."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" internet bağlantısı zayıf."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Bağlantıya izin verilsin mi?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s uygulaması %2$s Kablosuz Ağına bağlanmak istiyor"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Bir uygulama"</string>
@@ -1634,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Yöneticiniz tarafından yüklendi"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Yöneticiniz tarafından güncellendi"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Yöneticiniz tarafından silindi"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Pil tasarrufu özelliği, pil ömrünü iyileştirmeye yardımcı olmak için cihazın performansını düşürür, titreşimi, konum hizmetlerini ve arka plan verilerinin çoğunu sınırlar. Senkronizasyona dayalı olarak çalışan e-posta, mesajlaşma uygulamaları ve diğer uygulamalar, bunları açmadığınız sürece güncellenmeyebilir.\n\nCihazınız şarj olurken pil tasarrufu otomatik olarak kapatılır."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Pil Tasarrufu özelliği, pil ömrünü iyileştirmeye yardımcı olmak için cihazınızın performansını düşürür, titreşimi, konum hizmetlerini ve arka plan verilerinin çoğunu sınırlar. Senkronizasyona dayalı olarak çalışan e-posta, mesajlaşma uygulamaları ve diğer uygulamalar, bunları açmadığınız sürece güncellenmeyebilir.\n\nCihazınız şarj olurken Pil Tasarrufu otomatik olarak kapatılır."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Veri kullanımını azaltmaya yardımcı olması için Veri Tasarrufu, bazı uygulamaların arka planda veri göndermesini veya almasını engeller. Şu anda kullandığınız bir uygulama veri bağlantısına erişebilir, ancak bunu daha seyrek yapabilir. Bu durumda örneğin, siz resimlere dokunmadan resimler görüntülenmez."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Veri Tasarrufu açılsın mı?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Aç"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 7d14e59..ad6c6bc 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -81,7 +81,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Немає голосової/екстреної служби"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Тимчасово не пропонується мобільною мережею у вашому місцезнаходженні"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Не вдається під’єднатися до мережі"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Щоб покращити прийняття сигналу, змініть тип у меню \"Налаштування\" > \"Мережа й Інтернет\" > \"Мобільні мережі\" > \"Тип мережі\"."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Щоб покращити прийняття сигналу, змініть тип у меню \"Налаштування\" > \"Мережа й Інтернет\" > \"Мобільні мережі\" > \"Тип мережі\"."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Виклики через Wi-Fi активовано"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Щоб здійснювати екстрені виклики, потрібне з’єднання з мобільною мережею."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Сповіщення"</string>
@@ -216,6 +216,8 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Вимкнути"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Екстрений виклик"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Звіт про помилки"</string>
+ <!-- no translation found for global_action_logout (935179188218826050) -->
+ <skip />
<string name="bugreport_title" msgid="2667494803742548533">"Звіт про помилку"</string>
<string name="bugreport_message" msgid="398447048750350456">"Інформація про поточний стан вашого пристрою буде зібрана й надіслана електронною поштою. Підготовка звіту триватиме певний час."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Інтерактивний звіт"</string>
@@ -261,7 +263,7 @@
<string name="foreground_service_apps_in_background" msgid="7175032677643332242">"Додатків, що використовують заряд акумулятора: <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="foreground_service_tap_for_details" msgid="372046743534354644">"Торкніться, щоб перевірити використання акумулятора й трафік"</string>
<string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
- <string name="safeMode" msgid="2788228061547930246">"Безп. режим"</string>
+ <string name="safeMode" msgid="2788228061547930246">"Безпечний режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
<string name="user_owner_label" msgid="1119010402169916617">"Перейти в особистий профіль"</string>
<string name="managed_profile_label" msgid="5289992269827577857">"Перейти в робочий профіль"</string>
@@ -1091,6 +1093,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Знову ввімкнути це в меню Налаштування системи > Програми > Завантажені."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> не підтримує поточне налаштування розміру екрана та може працювати неналежним чином."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Завжди показувати"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> несумісний із вашою версією ОС Android і може працювати неналежним чином. Можливо, доступна оновлена версія додатка."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Завжди показувати"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Шукати оновлення"</string>
<string name="smv_application" msgid="3307209192155442829">"Програма <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) порушила свою самозастосовну політику StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Процес <xliff:g id="PROCESS">%1$s</xliff:g> порушив свою самозастосовну політику StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android оновлюється..."</string>
@@ -1160,10 +1165,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Вхід у мережу"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Мережа Wi-Fi не має доступу до Інтернету"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Мережа Wi-Fi не має доступу до Інтернету"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Торкніться, щоб відкрити опції"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Пристрій перейшов на мережу <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Пристрій використовує мережу <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, коли мережа <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> не має доступу до Інтернету. Може стягуватися плата."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Коли мережа <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> не має доступу до Інтернету, використовується <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Може стягуватися плата."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Пристрій перейшов з мережі <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на мережу <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"мобільне передавання даних"</item>
@@ -1174,7 +1179,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"невідомий тип мережі"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не вдалося під’єднатися до мережі Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" має погане з’єднання з Інтернетом."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" має погане з’єднання з Інтернетом."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дозволити з’єднання?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Додаток %1$s хоче під’єднатися до мережі Wi-Fi \"%2$s\""</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Додаток"</string>
@@ -1543,6 +1548,10 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Коли ярлик увімкнено, після натискання обох клавіш гучності й утримування їх протягом 3 секунд увімкнеться функція спеціальних можливостей.\n\n Поточна функція спеціальних можливостей:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Цю функцію можна змінити в меню \"Налаштування\" > \"Спеціальні можливості\"."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Вимкнути ярлик"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Використовувати ярлик"</string>
+ <!-- no translation found for color_inversion_feature_name (4231186527799958644) -->
+ <skip />
+ <!-- no translation found for color_correction_feature_name (6779391426096954933) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Ярлик спеціальних можливостей увімкнув <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Ярлик спеціальних можливостей вимкнув <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Виберіть функцію для кнопки спеціальних можливостей:"</string>
@@ -1676,7 +1685,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2-а робота: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3-я робота: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Щоб відкріпити цей екран, натисніть і втримуйте кнопки \"Назад\" та \"Огляд\""</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Не вдається відкріпити цей додаток"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Екран закріплено"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Екран відкріплено"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"PIN-код для відкріплення"</string>
@@ -1685,7 +1693,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Установлено адміністратором"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Оновлено адміністратором"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Видалено адміністратором"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Щоб подовжити час роботи акумулятора, функція заощадження заряду акумулятора знижує продуктивність пристрою, а також обмежує вібрацію, функції служб локації та передавання більшості фонових даних. Електронна пошта, чати й інші додатки, які синхронізуються, можуть не оновлюватися, доки ви їх не відкриєте.\n\nФункція заощадження заряду акумулятора автоматично вимикається під час заряджання пристрою."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Щоб подовжити час роботи акумулятора, у режимі економії заряду акумулятора знижується продуктивність пристрою й обмежуються вібрація, функції служб локації та фоновий режим обміну даними. Електронна пошта, чати й інші додатки, які синхронізуються, можуть не оновлюватися, доки ви їх не відкриєте.\n\nРежим економії заряду акумулятора автоматично вимикається під час заряджання пристрою."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Щоб зменшити використання трафіку, функція \"Заощадження трафіку\" не дозволяє деяким додаткам надсилати чи отримувати дані у фоновому режимі. Поточний додаток зможе отримувати доступ до таких даних, але рідше. Наприклад, зображення не відображатиметься, доки ви не торкнетеся його."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Увімкнути Заощадження трафіку?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Увімкнути"</string>
@@ -1748,6 +1756,8 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Увечері в будні"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"На вихідних"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Подія"</string>
+ <!-- no translation found for zen_mode_default_every_night_name (3012363838882944175) -->
+ <skip />
<string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> вимикає звук"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Через внутрішню помилку ваш пристрій може працювати нестабільно. Відновіть заводські налаштування."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"На пристрої сталася внутрішня помилка. Зв’яжіться з виробником пристрою, щоб дізнатися більше."</string>
@@ -1852,14 +1862,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Перевірка екстрених повідомлень"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Відповісти"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"Голосові дзвінки із SIM-карти заборонено"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"Не вказано SIM-карту для голосових дзвінків"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"Голосові дзвінки із SIM-карти заборонено"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Голосові дзвінки з телефона заборонено"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Спливаюче вікно"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Для цього ярлика потрібна найновіша версія додатка"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index f009e08..6774754 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"کوئی صوتی/ہنگامی سروس نہیں"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"عارضی طور پر آپ کے مقام پر موبائل نیٹ ورک کی طرف سے پیش نہیں ہے"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"نیٹ ورک تک نہیں پہنچا جا سکتا"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"ریسپشن کو بہتر بنانے کیلئے، ترتیبات > نیٹ ورک اور انٹرنیٹ > موبائل نیٹ ورکس > ترجیحی نیٹ ورک کی قسم تبدیل کرنے کی کوشش کریں۔"</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"ریسپشن کو بہتر بنانے کیلئے، ترتیبات > نیٹ ورک اور انٹرنیٹ > موبائل نیٹ ورکس > ترجیحی نیٹ ورک کی قسم تبدیل کر کے دیکھیں۔"</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi-Fi کالنگ فعال ہے"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"ہنگامی کالز کو موبائل نیٹ ورک کی ضرورت ہے۔"</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"الرٹس"</string>
@@ -1051,6 +1051,10 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"سسٹم ترتیبات > ایپس > ڈاؤن لوڈ کردہ میں اسے دوبارہ فعال کریں۔"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> میں موجودہ ڈسپلے سائز ترتیبات کی معاونت نہیں ہے اور ہو سکتا ہے غیر متوقع طریقے سے کام کرے۔"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ہمیشہ دکھائیں"</string>
+ <!-- no translation found for unsupported_compile_sdk_message (4253168368781441759) -->
+ <skip />
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"ہمیشہ دکھائیں"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"اپ ڈیٹ چیک کریں"</string>
<string name="smv_application" msgid="3307209192155442829">"ایپ <xliff:g id="APPLICATION">%1$s</xliff:g> (کارروائی <xliff:g id="PROCESS">%2$s</xliff:g>) نے خود نافذ کی گئی StrictMode پالیسی کی خلاف ورزی کی ہے۔"</string>
<string name="smv_process" msgid="5120397012047462446">"کارروائی <xliff:g id="PROCESS">%1$s</xliff:g> نے اپنی ذاتی طور پر نافذ کردہ StrictMode پلیسی کی خلاف ورزی کی ہے۔"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android اپ گریڈ ہو رہا ہے…"</string>
@@ -1116,10 +1120,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"نیٹ ورک میں سائن ان کریں"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi کی انٹرنیٹ تک رسائی نہیں ہے"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi کو انٹرنیٹ تک رسائی نہیں ہے"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"اختیارات کیلئے تھپتھپائیں"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> پر سوئچ ہو گیا"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"جب <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> کے پاس انٹرنیٹ تک رسائی نہ ہو تو آلہ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> کو استعمال کرتا ہے۔ چارجز کا اطلاق ہو سکتا ہے۔"</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"جب <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> کو انٹرنیٹ تک رسائی نہیں ہوتی ہے تو آلہ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> کا استعمال کرتا ہے۔ چارجز لاگو ہو سکتے ہیں۔"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> سے <xliff:g id="NEW_NETWORK">%2$s</xliff:g> پر سوئچ ہو گیا"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"موبائل ڈیٹا"</item>
@@ -1130,7 +1134,8 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"نیٹ ورک کی نامعلوم قسم"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi سے مربوط نہیں ہو سکا"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" اس میں ایک کمزور انٹرنیٹ کنکشن ہے۔"</string>
+ <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+ <skip />
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"کنکشن کی اجازت دیں؟"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"ایپلیکیشن %1$s Wifi نیٹ ورک %2$s سے منسلک ہونا چاہتی ہے"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"ایک ایپلیکیشن"</string>
@@ -1634,7 +1639,8 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"آپ کے منتظم کے ذریعے انسٹال کیا گیا"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"آپ کے منتظم کے ذریعے اپ ڈیٹ کیا گیا"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"آپ کے منتظم کے ذریعے حذف کیا گیا"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"بیٹری کی میعاد بہتر کرنے میں مدد کرنے کیلئے، بیٹری سیور آپ کے آلہ کی کارکردگی کم کر دیتی ہے اور وائبریشن، مقام کی سروسز اور پس منظر کا بیشتر ڈیٹا محدود کر دیتی ہے۔ ای میل، پیغام رسانی اور مطابقت پذیری پر منحصر دیگر ایپس ممکن ہے اس وقت تک اپ ڈیٹ نہ ہوں جب تک آپ انہیں نہ کھولیں۔\n\nآپ کا آلہ چارج ہوتے وقت بیٹری سیور خود بخود آف ہو جاتی ہے۔"</string>
+ <!-- no translation found for battery_saver_description (5394663545060026162) -->
+ <skip />
<string name="data_saver_description" msgid="6015391409098303235">"ڈیٹا کے استعمال کو کم کرنے میں مدد کیلئے، ڈیٹا سیور پس منظر میں کچھ ایپس کو ڈیٹا بھیجنے یا موصول کرنے سے روکتا ہے۔ آپ جو ایپ فی الحال استعمال کر رہے ہیں وہ ڈیٹا پر رسائی کر سکتی ہے مگر ہو سکتا ہے ایسا زیادہ نہ ہو۔ اس کا مطلب مثال کے طور پر یہ ہو سکتا ہے کہ تصاویر تھپتھپانے تک ظاہر نہ ہوں۔"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ڈیٹا سیور آن کریں؟"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"آن کریں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index af5e0bd..52f46df 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Ovozli va favqulodda chaqiruvlar ishlamaydi"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Hududingizda mobil tarmoq tomonidan vaqtinchalik taklif etilmayapti"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Tarmoq bilan bog‘lanib bo‘lmadi"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Qabul qilish sifatini yaxshilash uchun Sozlamalar > Tarmoq va Internet > Mobil tarmoqlar > Asosiy tarmoq turi orqali o‘zgartirib ko‘ring."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Qabul qilish sifatini yaxshilash uchun Sozlamalar > Tarmoq va Internet > Mobil tarmoqlar > Asosiy tarmoq turi orqali o‘zgartirib ko‘ring."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi chaqiruv faol"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Favqulodda chaqiruvlar uchun mobil internet zarur."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Ogohlantirishlar"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Uni Tizim sozlamalari > Ilovalar > Yuklab olingan menyusidan qayta yoqing."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” ilovasi joriy ekran o‘lchami sozlamalariga mos kelmasligi va noto‘g‘ri ishlashi mumkin."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Har doim ko‘rsatilsin"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi boshqa Android OS versiyasi uchun ishlab chiqarilgan va xato ishlashi mumkin. Ilovaning yangilangan versiyasi chiqqan bo‘lishi kerak."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Doim ko‘rsatilsin"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Yangilanish borligini tekshirish"</string>
<string name="smv_application" msgid="3307209192155442829">"“<xliff:g id="APPLICATION">%1$s</xliff:g>” ilovasi (jarayaon: <xliff:g id="PROCESS">%2$s</xliff:g>) o‘zining StrictMode qoidasini buzdi."</string>
<string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> jarayoni o‘zining o‘zi-bajaruvchi StrictMode siyosatini buzdi."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android yangilanmoqda…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Tarmoqqa kirish"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi tarmog‘ida internet aloqasi yo‘q"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi tarmoqda internet aloqasi yo‘q"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Variantlarni ko‘rsatish uchun bosing"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> tarmog‘iga ulanildi"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Qurilma <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tarmog‘ida internet o‘chganda, <xliff:g id="NEW_NETWORK">%1$s</xliff:g> tarmog‘iga ulaniladi. To‘lov olinishi mumkin."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Agar <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tarmoqda internet uzilsa, qurilma <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ga ulanadi. Sarflangan trafik uchun haq olinishi mumkin."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> tarmog‘idan <xliff:g id="NEW_NETWORK">%2$s</xliff:g> tarmog‘iga o‘tildi"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"mobil internet"</item>
@@ -1130,7 +1133,8 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"noma’lum tarmoq turi"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi’ga ulana olmadi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tezligi past Internetga ulangan."</string>
+ <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+ <skip />
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ulanishga ruxsat berilsinmi?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s ilovasi %2$s Wi-Fi tarmog‘iga ulanmoqchi"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Ilova"</string>
@@ -1634,7 +1638,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Administrator tomonidan o‘rnatilgan"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Administrator tomonidan yangilangan"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Administrator tomonidan o‘chirilgan"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Batareya quvvatini uzoqroq vaqtga yetkazish uchun quvvat tejash funksiyasi qurilmangiz unumdorligini kamaytiradi hamda uning tebranishi va orqa fonda internetdan foydalanishini cheklaydi. Sinxronlanishni talab qiladigan e-pochta, xabar almashinuv va boshqa ilovalar esa qachonki ularni ishga tushirganingizda yangilanadi.\n\nQurilma quvvat olayotganda quvvat tejash funksiyasi avtomatik tarzda o‘chadi."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Batareya quvvatini uzoqroq vaqtga yetkazish uchun quvvat tejash funksiyasi qurilmangiz unumdorligini kamaytiradi hamda uning tebranishi va orqa fonda internetdan foydalanishini cheklaydi. Sinxronlanishni talab qiladigan e-pochta, xabar almashinuv va boshqa ilovalar esa qachonki ularni ishga tushirganingizda yangilanadi.\n\nQurilma quvvat olayotganda quvvat tejash funksiyasi avtomatik tarzda o‘chadi."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Trafik tejash rejimida ayrim ilovalar uchun orqa fondan internetdan foydalanish imkoniyati cheklanadi. Siz ishlatayotgan ilova zaruratga qarab internet-trafik sarflashi mumkin, biroq cheklangan miqdorda. Masalan, rasmlar ustiga bosmaguningizcha ular yuklanmaydi."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Trafik tejash yoqilsinmi?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Yoqish"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index c3938aa..0ffbe00 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Không có dịch vụ thoại/khẩn cấp"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Tạm thời không được cung cấp bởi mạng di động tại vị trí của bạn"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Không thể kết nối mạng"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Để cải thiện khả năng thu tín hiệu, hãy thử thay đổi loại mạng được chọn trong Cài đặt > Mạng và Internet > Mạng di động > Loại mạng ưu tiên."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Để cải thiện khả năng thu tín hiệu, hãy thử thay đổi loại mạng được chọn trong phần Cài đặt > Mạng và Internet > Mạng di động > Loại mạng ưa thích."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Gọi qua Wi‑Fi đang hoạt động"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Cuộc gọi khẩn cấp yêu cầu có mạng di động."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Thông báo"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Bật lại chế độ này trong cài đặt Hệ thống > Ứng dụng > Đã tải xuống."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> không hỗ trợ cài đặt kích thước Màn hình hiện tại và có thể hoạt động không như mong đợi."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Luôn hiển thị"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> được xây dựng cho phiên bản không tương thích của hệ điều hành Android và có thể hoạt động không như mong đợi. Bạn có thể sử dụng phiên bản cập nhật của ứng dụng."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Luôn hiển thị"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Kiểm tra bản cập nhật"</string>
<string name="smv_application" msgid="3307209192155442829">"Ứng dụng <xliff:g id="APPLICATION">%1$s</xliff:g> (quá trình <xliff:g id="PROCESS">%2$s</xliff:g>) đã vi phạm chính sách StrictMode tự thi hành của mình."</string>
<string name="smv_process" msgid="5120397012047462446">"Quá trình <xliff:g id="PROCESS">%1$s</xliff:g> đã vi phạm chính sách StrictMode tự thi hành của mình."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android đang nâng cấp..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Đăng nhập vào mạng"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi không có quyền truy cập Internet"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi không có quyền truy cập Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Nhấn để biết tùy chọn"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Đã chuyển sang <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Thiết bị sử dụng <xliff:g id="NEW_NETWORK">%1$s</xliff:g> khi <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> không có quyền truy cập Internet. Bạn có thể phải trả phí."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Thiết bị sử dụng <xliff:g id="NEW_NETWORK">%1$s</xliff:g> khi <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> không có quyền truy cập Internet. Bạn có thể phải trả phí."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Đã chuyển từ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> sang <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"dữ liệu di động"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"loại mạng không xác định"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Không thể kết nối với Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" có kết nối Internet không tốt."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" có kết nối internet kém."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Cho phép kết nối?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Ứng dụng %1$s muốn kết nối với Mạng Wifi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Ứng dụng"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Công việc thứ 2 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Công việc thứ 2 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Để bỏ ghim màn hình này, chạm và giữ nút Quay lại và Tổng quan"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Không thể bỏ ghim ứng dụng này"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Đã ghim màn hình"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Đã bỏ ghim màn hình"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Hỏi mã PIN trước khi bỏ ghim"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Do quản trị viên của bạn cài đặt"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Do quản trị viên của bạn cập nhật"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Do quản trị viên của bạn xóa"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Để giúp tăng thời lượng pin, trình tiết kiệm pin sẽ giảm hiệu suất thiết bị và hạn chế rung, dịch vụ vị trí và hầu hết dữ liệu nền. Ứng dụng email, nhắn tin và các ứng dụng khác dựa trên đồng bộ hóa có thể không cập nhật nếu bạn không mở.\n\nTrình tiết kiệm pin tự động tắt khi thiết bị của bạn đang sạc."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Để giúp tăng thời lượng pin, Trình tiết kiệm pin sẽ giảm hiệu suất thiết bị và hạn chế rung, dịch vụ vị trí và hầu hết dữ liệu nền. Ứng dụng email, nhắn tin và các ứng dụng khác sử dụng đồng bộ hóa có thể không cập nhật nếu bạn không mở chúng.\n\nTrình tiết kiệm pin tự động tắt khi thiết bị của bạn đang sạc."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Để giúp giảm mức sử dụng dữ liệu, Trình tiết kiệm dữ liệu chặn một số ứng dụng gửi hoặc nhận dữ liệu trong nền. Ứng dụng mà bạn hiện sử dụng có thể truy cập dữ liệu nhưng có thể thực hiện việc đó ít thường xuyên hơn. Ví dụ: hình ảnh sẽ không hiển thị cho đến khi bạn nhấn vào hình ảnh đó."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Bật Trình tiết kiệm dữ liệu?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Bật"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Kiểm tra thông báo khẩn cấp"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Trả lời"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM không được phép sử dụng tính năng thoại"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM không được cung cấp tính năng thoại"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM không được phép sử dụng tính năng thoại"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Điện thoại không được phép sử dụng tính năng thoại"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Cửa sổ bật lên"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Lối tắt này yêu cầu ứng dụng mới nhất"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 6b95eda..1765a7e 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"无法使用语音通话/紧急呼救服务"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"您所在位置的移动网络暂时不提供这项服务"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"无法连接网络"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"要改善信号情况,请尝试更改在“设置”>“网络和互联网”>“移动网络”>“首选网络类型”中选择的类型。"</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"要改善信号情况,请尝试更改在“设置”>“网络和互联网”>“移动网络”>“首选网络类型”中选择的类型。"</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"正在进行 WLAN 通话"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"紧急呼救需要使用移动网络。"</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"提醒"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"在“系统设置”>“应用”>“已下载”中重新启用此模式。"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g>不支持当前的显示大小设置,因此可能无法正常显示。"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"一律显示"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g>是专为不兼容的 Android 操作系统版本所打造的应用,因此可能会出现意外行为。您可以使用该应用的更新版本。"</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"一律显示"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"检查更新"</string>
<string name="smv_application" msgid="3307209192155442829">"“<xliff:g id="APPLICATION">%1$s</xliff:g>”应用(<xliff:g id="PROCESS">%2$s</xliff:g> 进程)违反了自我强制执行的严格模式 (StrictMode) 政策。"</string>
<string name="smv_process" msgid="5120397012047462446">"进程 <xliff:g id="PROCESS">%1$s</xliff:g> 违反了自我强制执行的严格模式 (StrictMode) 政策。"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android正在升级..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"登录到网络"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"此 WLAN 网络无法访问互联网"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"此 WLAN 网络无法访问互联网"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"点按即可查看相关选项"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"已切换至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"设备会在无法连接到<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>时使用<xliff:g id="NEW_NETWORK">%1$s</xliff:g>(可能需要支付相应的费用)。"</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"设备会在<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>无法访问互联网时使用<xliff:g id="NEW_NETWORK">%1$s</xliff:g>(可能需要支付相应的费用)。"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"已从<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切换至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"移动数据"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"未知网络类型"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"无法连接到WLAN"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 互联网连接状况不佳。"</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" 互联网连接状况不佳。"</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"要允许连接吗?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"“%1$s”应用想要连接到 WLAN 网络“%2$s”"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"一款应用"</string>
@@ -1634,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"已由您的管理员安装"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"已由您的管理员更新"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"已由您的管理员删除"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"为了延长电池的续航时间,省电模式会降低设备的性能,并限制振动、位置信息服务和大部分后台流量。对于电子邮件、聊天工具等依赖于同步功能的应用,可能要打开这类应用时才能收到新信息。\n\n省电模式会在设备充电时自动关闭。"</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"为了延长电池的续航时间,省电模式会降低设备的性能,并限制振动、位置信息服务和大部分后台流量。对于电子邮件、聊天工具等依赖于同步功能的应用,可能要打开这类应用时才能收到新信息。\n\n省电模式会在设备充电时自动关闭。"</string>
<string name="data_saver_description" msgid="6015391409098303235">"为了减少流量消耗,流量节省程序会阻止某些应用在后台收发数据。您当前使用的应用可以收发数据,但频率可能会降低。举例而言,这可能意味着图片只有在您点按之后才会显示。"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"要开启流量节省程序吗?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"开启"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index b9c83b3..47bf16b 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"沒有語音/緊急服務"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"您所在位置的流動網絡暫不提供這項服務"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"無法連接網絡"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"如要接收更強訊號,請前往 [設定] > [網絡與互聯網] > [流動網絡] > [偏好的網絡類型] 更改網絡類型。"</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"如要接收更強訊號,請前往 [設定] > [網絡與互聯網] > [流動網絡] > [偏好的網絡類型] 更改網絡類型。"</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"正在進行 Wi-Fi 通話"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"撥打緊急電話需要使用流動網絡"</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"通知"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"前往 [系統設定] > [應用程式] > [下載] 重新啟用這個模式。"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援目前的「螢幕」尺寸設定,畫面可能無法如預期顯示。"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"永遠顯示"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」是專為不兼容 Android OS 版本所打造的應用程式,因此可能無法正常運作。您可能可以使用該應用程式的更新版本。"</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"一律顯示"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"檢查更新"</string>
<string name="smv_application" msgid="3307209192155442829">"應用程式 <xliff:g id="APPLICATION">%1$s</xliff:g> (處理程序 <xliff:g id="PROCESS">%2$s</xliff:g>) 已違反其自行強制實施的嚴格模式 (StrictMode) 政策。"</string>
<string name="smv_process" msgid="5120397012047462446">"處理程序 <xliff:g id="PROCESS">%1$s</xliff:g> 已違反其自行強制實施的嚴格模式 (StrictMode) 政策。"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"正在升級 Android..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"登入網絡"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi 並未連接互聯網"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi 並未連接互聯網"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"輕按即可查看選項"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"當<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>無法連線至互聯網時,裝置便會切換至<xliff:g id="NEW_NETWORK">%1$s</xliff:g>。可能需要支付額外費用。"</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"裝置會在 <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> 無法連線至互聯網時使用<xliff:g id="NEW_NETWORK">%1$s</xliff:g> (可能需要支付相關費用)。"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"已從<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"流動數據"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"不明網絡類型"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"無法連線至 Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 互聯網連線欠佳。"</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" 互聯網連線欠佳。"</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"允許連線?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"應用程式 %1$s 要求連線至 WiFi 網絡 %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"應用程式"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"第二個工作<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"第三個工作<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"如要取消固定此畫面,請按住 [返回] 和 [概覽] 按鈕"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"無法取消固定此應用程式"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"螢幕已固定"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"已取消固定螢幕"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消固定時必須輸入 PIN"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"已由您的管理員安裝"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"已由您的管理員更新"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"已由您的管理員刪除"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"為延長電池壽命,省電模式會降低裝置效能,並限制震動、位置資訊服務及大部分背景數據傳輸。如電郵、短訊及其他使用同步功能的應用程式沒有開啟,便不會自動更新。\n\n裝置充電時,省電模式會自動關閉。"</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"為延長電池壽命,省電模式會降低裝置效能,並限制震動、位置資訊服務及大部分背景數據的使用。除非您啟用有關程式,否則電郵、短訊及其他需要使用同步功能的應用程式均不會更新。\n\n省電模式會在裝置充電時自動關閉。"</string>
<string name="data_saver_description" msgid="6015391409098303235">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。您正在使用的應用程式可存取資料,但次數可能會減少。例如,圖片可能需要輕按才會顯示。"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"要開啟「數據節省模式」嗎?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"開啟"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"緊急訊息測試"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"回覆"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM 卡不支援語音"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"未佈建支援語音的 SIM 卡"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM 卡不支援語音"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"手機不支援語音"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"彈出式視窗"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"您需要最新的應用程式,才能使用這個捷徑"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index a5b91eb..f050dfe 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"無法使用語音/緊急通話服務"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"你所在位置的行動網路暫時不提供這項服務"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"無法連上網路"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"如要改善收訊狀況,請依序開啟 [設定] > [網路與網際網路] > [行動網路] > [偏好的網路類型],然後選取其他網路類型。"</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"如要改善收訊狀況,請依序開啟 [設定] > [網路與網際網路] > [行動網路] > [偏好的網路類型],然後選取其他網路類型。"</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi 通話正在進行中"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"撥打緊急電話需要使用行動網路"</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"快訊"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"前往 [系統設定] > [應用程式] > [下載] 重新啟用這個模式。"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援目前的顯示大小設定,可能會發生非預期的行為。"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"一律顯示"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」是專為 Android 作業系統的不相容版本所打造的應用程式,因此目前可能無法正常運作。你可以使用該應用程式的更新版本。"</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"一律顯示"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"檢查更新"</string>
<string name="smv_application" msgid="3307209192155442829">"應用程式 <xliff:g id="APPLICATION">%1$s</xliff:g> (處理程序 <xliff:g id="PROCESS">%2$s</xliff:g>) 已違反其自行強制實施的嚴格模式 (StrictMode) 政策。"</string>
<string name="smv_process" msgid="5120397012047462446">"處理程序 <xliff:g id="PROCESS">%1$s</xliff:g> 已違反其自行強制實施的嚴格模式 (StrictMode) 政策。"</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"正在升級 Android…"</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"登入網路"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi 網路沒有網際網路連線"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi 沒有網際網路連線"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"輕觸即可查看選項"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"裝置會在無法連上 <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> 時切換至<xliff:g id="NEW_NETWORK">%1$s</xliff:g> (可能需要支付相關費用)。"</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"裝置會在無法連上「<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>」時切換至「<xliff:g id="NEW_NETWORK">%1$s</xliff:g>」(可能需要支付相關費用)。"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"已從 <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> 切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"行動數據"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"不明的網路類型"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"無法連線至 Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 的網際網路連線狀況不佳。"</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" 網際網路連線狀況不佳。"</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"允許連線?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"「%1$s」應用程式要求連線至 WiFi 網路 %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"應用程式"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"第 2 項工作:<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"第 3 項工作:<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"如要取消固定這個畫面,請按住「返回」按鈕和「總覽」按鈕"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"無法取消固定這個應用程式"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"已固定螢幕"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"已取消固定螢幕"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消固定時必須輸入 PIN"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"已由你的管理員安裝"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"已由你的管理員更新"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"已由你的管理員刪除"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"為了延長電池續航力,節約耗電量模式會降低裝置效能,並限制震動、定位服務及大部分背景數據傳輸。此外,如果未開啟電子郵件、簡訊和其他需要使用同步功能的應用程式,系統將不會自動更新這些應用程式。\n\n當你為裝置充電時,節約耗電量模式會自動關閉。"</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"為了延長電池續航力,節約耗電量模式會降低裝置效能,並限制震動、定位服務及大部分背景數據傳輸。此外,如果未開啟電子郵件、簡訊和其他需要使用同步功能的應用程式,系統將不會自動更新這些應用程式。\n\n當你為裝置充電時,節約耗電量模式會自動關閉。"</string>
<string name="data_saver_description" msgid="6015391409098303235">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。你目前使用的某個應用程式可以存取資料,但存取頻率可能不如平時高。舉例來說,圖片可能不會自動顯示,而必須由你輕觸後才會顯示。"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"要開啟數據節省模式嗎?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"開啟"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"緊急訊息測試"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"回覆"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM 卡不支援語音"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"未佈建支援語音的 SIM 卡"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM 卡不支援語音"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"手機不支援語音"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"彈出式視窗"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"你必須擁有最新版的應用程式,才能使用這個捷徑"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 4703e79..3311d79a 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -79,7 +79,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Ayikho isevisi yezwi/yesimo esiphuthumayo"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Okwesikhashana akunikezwa inethiwekhi yeselula endaweni yakho"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Ayikwazi ukufinyelela inethiwekhi"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Ukuze uthuthukise ukwamukelwa, zama ukushintsha uhlobo olukhethiwe kuzilungiselelo > Inethiwekhi ne-inthanethi > amanethiwekhi eselula > Uhlobo oluncanyelwayo lwenethiwekhi."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"Ukuze uthuthukise ukwamukela, zama ukushintsha uhlobo olukhethiwe kuzilungiselelo > Inethiwekhi ne-inthanethi > Amanethiwekhi eselula > Uhlobo lwenethiwekhi oluncanyelwayo."</string>
<string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Ukushaya kwe-Wi-Fi kuyasebenza"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Amakholi aphuthumayo adinga inethiwekhi yeselula."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Izexwayiso"</string>
@@ -1051,6 +1051,9 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Yenza kuphinde kusebenze kuzilungiselelo Zesistimue > Izinhlelo zokusebenza > Okulayishiwe."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayisekeli isilungiselelo sosayizi sokubonisa samanje futhi ingasebenza ngokungalindelekile."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Bonisa njalo"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> yakhiwe kunguqulo engahambisani ye-Android OS futhi ingaziphatha ngokungalindelekile. Inguqulo ebuyekeziwe yohlelo lokusebenza ingatholakala."</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Bonisa njalo"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Hlola izibuyekezo"</string>
<string name="smv_application" msgid="3307209192155442829">"Inqubo <xliff:g id="APPLICATION">%1$s</xliff:g> (yohlelo <xliff:g id="PROCESS">%2$s</xliff:g>) iphule inqubomgomo oziphoqelela yona Yemodi Ebukhali."</string>
<string name="smv_process" msgid="5120397012047462446">"Inqubo <xliff:g id="PROCESS">%1$s</xliff:g> yephule inqubomgomo yokuziphoqelela Yemodi Ebukhali."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"I-Android ifaka ezakamuva..."</string>
@@ -1116,10 +1119,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Ngena ngemvume kunethiwekhi"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"I-Wi-Fi ayinakho ukufinyelela kwe-inthanethi"</string>
+ <string name="wifi_no_internet" msgid="8938267198124654938">"I-Wi-Fi ayinakho ukufinyelela kwe-inthanethi"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Thepha ukuze uthole izinketho"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Kushintshelwe ku-<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"Idivayisi isebenzisa i-<xliff:g id="NEW_NETWORK">%1$s</xliff:g> uma i-<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ingenakho ukufinyelela kwe-inthanethi. Izindleko zingasebenza."</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"Idivayisi isebenzisa i-<xliff:g id="NEW_NETWORK">%1$s</xliff:g> uma i-<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> inganakho ukufinyelela kwe-inthanethi. Kungasebenza izindleko."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Kushintshelewe kusuka ku-<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kuya ku-<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"idatha yeselula"</item>
@@ -1130,7 +1133,7 @@
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"uhlobo olungaziwa lwenethiwekhi"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ayikwazanga ukuxhuma kwi-Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" inoxhumano oluphansi lwe-inthanethi."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" inoxhumano oluphansi lwe-inthanethi."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vumela ukuxhumeka?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Uhlelo lokusebenza %1$s lungathanda ukuxhuma kunethiwekhi ye-Wifi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Uhlelo lokusebenza"</string>
@@ -1626,7 +1629,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Umsebenzi wesibili <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Umsebenzi wesithathu <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Ukuze ususe ukuphina lesi sikrini, thinta uphinde ubambe izinkinobho zokubuyela emuva nezokubuka konke"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Lolu hlelo lokusebenza alukwazi ukususwa ukuphinwa"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Isikrini siphiniwe"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Isikrini sisuswe ukuphina"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Cela iphinikhodi ngaphambi kokuphina"</string>
@@ -1635,7 +1637,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Kufakwe umlawuli wakho"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Kubuyekezwe umlawuli wakho"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Kususwe umlawuli wakho"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Ukusiza ukuthuthukisa impilo yebhethri, isilondoloze sebhethri sehlisa ukusebenza kwedivayisi yakho futhi sikhawulele ukudlidliza, amasevisi wendawo, nedatha eningi yangasemuva. I-imeyili, imilayezo, nezinye izinhlelo zokusebenza ezincike ekuvumelaniseni zingahle zingabuyekezwa ngaphandle kokuthi uzivule.\n\nIsilondolozi sebhethri siyavaleka ngokuzenzakalelayo uma idivayisi yakho ishaja."</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"Ukuze kusizwe ukuthuthukisa impilo yebhethri, isilondolozi sebhethri sehlisa ukusebenza kwedivayisi yakho kuphinde kukhawulele ukudlidliza, amasevisi endawo kanye nedatha eningi yasemuva. I-imeyili, ukulayeza nezinye izinhlelo zokusebenza ezithembele ekuvunyelanisweni kungenzeka zingabuyekezwa ngaphandle kokuthi uzivule.\n\nIsilondolozi sebhethri sivalwa ngokuzenzakalela uma idivayisi yakho ishaja."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Ukusiza ukwehlisa ukusetshenziswa kwedatha, iseva yedatha igwema ezinye izinhlelo zokusebenza ukuthi zithumele noma zamukele idatha ngasemuva. Uhlelo lokusebenza olisebenzisa okwamanje lingafinyelela idatha, kodwa lingenza kanjalo kancane. Lokhu kungachaza, isibonelo, ukuthi izithombe azibonisi uze uzithephe."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Vula iseva yedatha?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Vula"</string>
@@ -1782,14 +1784,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Ukuhlolwa kwemilayezo yesimo esiphuthumayo"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Phendula"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"I-SIM ayivunyelwe kwizwi"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"I-SIM ayinikezelwe izwi"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"I-SIM ayivunyelwe kwizwi"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Ifoni ayivunyelwe izwi"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Iwindi lesigelekeqe"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Lesi sinqamuleli sidinga uhlelo lokusebenza lwakamuva"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0eefec9..51ffa60 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1016,6 +1016,9 @@
<!-- Style for the "neutral" buttons within button bars. -->
<attr name="buttonBarNeutralButtonStyle" format="reference" />
+ <!-- Corner radius of buttons. -->
+ <attr name="buttonCornerRadius" format="dimension" />
+
<!-- Style for the search query widget. -->
<attr name="searchViewStyle" format="reference" />
@@ -3021,6 +3024,12 @@
<!-- Whether this View should use a default focus highlight when it gets focused but
doesn't have {@link android.R.attr#state_focused} defined in its background. -->
<attr name="defaultFocusHighlightEnabled" format="boolean" />
+
+ <!-- Whether this view should be treated as a focusable unit by screen reader accessibility
+ tools. See {@link android.view.View#setScreenReaderFocusable(boolean)}. The default
+ value, {@code false}, leaves the screen reader to consider other signals, such as
+ focusability or the presence of text, to decide what it focus.-->
+ <attr name="screenReaderFocusable" format="boolean" />
</declare-styleable>
<!-- Attributes that can be assigned to a tag for a particular View. -->
@@ -3285,6 +3294,9 @@
and subtype in order to provide the consistent user experience in switching
between IMEs and subtypes. -->
<attr name="supportsSwitchingToNextInputMethod" format="boolean" />
+ <!-- Specifies if an IME can only be used while a device is in VR mode or on a dedicated
+ device -->
+ <attr name="isVrOnly" format="boolean"/>
<attr name="__removed2" format="boolean" />
</declare-styleable>
@@ -7559,6 +7571,15 @@
<flag name="keyguard" value="0x2" />
<flag name="searchbox" value="0x4" />
</attr>
+ <!-- Flags indicating various features supported by the widget. These are hints to the
+ widget host, and do not actually change the behavior of the widget. -->
+ <attr name="widgetFeatures" format="integer">
+ <!-- The widget can be reconfigured anytime after it is bound -->
+ <flag name="reconfigurable" value="0x1" />
+ <!-- The widget is added directly by the app, and does not need to appear in
+ the global list of available widgets -->
+ <flag name="hide_from_picker" value="0x2" />
+ </attr>
</declare-styleable>
<!-- =============================== -->
@@ -8529,6 +8550,8 @@
<attr name="maxWidth" />
<attr name="maxCollapsedHeight" format="dimension" />
<attr name="maxCollapsedHeightSmall" format="dimension" />
+ <!-- Whether the Drawer should be positioned at the top rather than at the bottom. -->
+ <attr name="showAtTop" format="boolean" />
</declare-styleable>
<declare-styleable name="MessagingLinearLayout">
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 4d410e5..e87b9d8 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -262,6 +262,9 @@
and the OEM has white-listed the app to receive this permission by the OEM.
-->
<flag name="oem" value="0x4000" />
+ <!-- Additional flag from base permission type: this permission can be granted to
+ privileged apps in vendor partition. -->
+ <flag name="vendorPrivileged" value="0x8000" />
</attr>
<!-- Flags indicating more context for a permission group. -->
@@ -317,6 +320,13 @@
as multiple split APKs, each APK must have the exact same versionCode. -->
<attr name="versionCode" format="integer" />
+ <!-- Internal major version code. This is essentially additional high bits
+ for the base version code; it has no other meaning than
+ that higher numbers are more recent. This is not a version
+ number generally shown to the user, that is usually supplied
+ with {@link android.R.attr#versionName}. -->
+ <attr name="versionCodeMajor" format="integer" />
+
<!-- Internal revision code. This number is the number used to determine
whether one APK is more recent than another: it has no other meaning
than that higher numbers are more recent. This value is only meaningful
@@ -1386,6 +1396,7 @@
{@link #AndroidManifestUsesFeature uses-feature}. -->
<declare-styleable name="AndroidManifest">
<attr name="versionCode" />
+ <attr name="versionCodeMajor" />
<attr name="versionName" />
<attr name="revisionCode" />
<attr name="sharedUserId" />
@@ -1784,6 +1795,10 @@
<attr name="name" />
<!-- Required specific library version. -->
<attr name="version" />
+ <!-- Required specific library major version code. This matches
+ android:versionCodeMajor of the library. -->
+ <!-- Required specific library version. -->
+ <attr name="versionMajor" format="integer" />
</declare-styleable>
<!-- The <code>uses-libraries</code> specifies a shared library that this
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c104616..0b38d1b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -565,6 +565,12 @@
<integer translatable="false" name="config_wifi_framework_wifi_score_good_link_speed_24">24</integer>
<integer translatable="false" name="config_wifi_framework_wifi_score_good_link_speed_5">36</integer>
+ <!-- Integer delay in milliseconds before shutting down soft AP when there
+ are no connected devices. Framework will enforce a minimum limit on
+ this value and this setting will be overridden if the provided value is
+ smaller than the limit. -->
+ <integer translatable="false" name="config_wifi_framework_soft_ap_timeout_delay">600000</integer>
+
<string translatable="false" name="config_wifi_random_mac_oui">DA-A1-19</string>
<string translatable="false" name="config_wifi_framework_sap_2G_channel_list">1,6,11</string>
@@ -1955,7 +1961,7 @@
<string name="config_dozeLongPressSensorType" translatable="false"></string>
<!-- Control whether the always on display mode is available. This should only be enabled on
- devices where the display has be tuned to be power efficient in DOZE and/or DOZE_SUSPEND
+ devices where the display has been tuned to be power efficient in DOZE and/or DOZE_SUSPEND
states. -->
<bool name="config_dozeAlwaysOnDisplayAvailable">false</bool>
@@ -2435,10 +2441,12 @@
"users" = list of users
"restart" = restart device
"lockdown" = Lock down device until the user authenticates
+ "logout" = Logout the current user
-->
<string-array translatable="false" name="config_globalActionsList">
<item>power</item>
<item>restart</item>
+ <item>logout</item>
<item>bugreport</item>
<item>users</item>
<item>lockdown</item>
@@ -3169,11 +3177,21 @@
classes are instantiated in the order of the array. -->
<string-array translatable="false" name="config_deviceSpecificSystemServices"></string-array>
+ <!-- Class name of the device specific implementation to replace the DevicePolicyManagerService
+ or empty if the default should be used. -->
+ <string translatable="false" name="config_deviceSpecificDevicePolicyManagerService"></string>
+
<!-- Component name of media projection permission dialog -->
<string name="config_mediaProjectionPermissionDialogComponent" translateable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string>
<!-- Corner radius of system dialogs -->
<dimen name="config_dialogCornerRadius">2dp</dimen>
+ <!-- Corner radius of system buttons -->
+ <dimen name="config_buttonCornerRadius">@dimen/control_corner_material</dimen>
+ <!-- Controls whether system buttons use all caps for text -->
+ <bool name="config_buttonTextAllCaps">true</bool>
+ <!-- Name of the font family used for system buttons -->
+ <string name="config_fontFamilyButton">@string/font_family_button_material</string>
<string translatable="false" name="config_batterySaverDeviceSpecificConfig"></string>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 946216c..a659b37 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -152,11 +152,11 @@
<dimen name="dialog_padding">16dp</dimen>
<!-- The margin on the start of the content view -->
- <dimen name="notification_content_margin_start">16dp</dimen>
+ <dimen name="notification_content_margin_start">24dp</dimen>
<!-- The margin on the end of the content view
Keep in sync with notification_content_plus_picture_margin! -->
- <dimen name="notification_content_margin_end">16dp</dimen>
+ <dimen name="notification_content_margin_end">24dp</dimen>
<!-- The margin on the end of the content view with a picture.
Keep in sync with notification_content_plus_picture_margin! -->
@@ -166,7 +166,7 @@
content end margin.
Keep equal to (notification_content_picture_margin + notification_content_margin_end)!
-->
- <dimen name="notification_content_plus_picture_margin_end">72dp</dimen>
+ <dimen name="notification_content_plus_picture_margin_end">80dp</dimen>
<!-- The additional margin on the sides of the ambient view. -->
<dimen name="notification_extra_margin_ambient">16dp</dimen>
@@ -175,10 +175,10 @@
<dimen name="notification_action_list_height">56dp</dimen>
<!-- height of the content margin to accomodate for the header -->
- <dimen name="notification_content_margin_top">37.5dp</dimen>
+ <dimen name="notification_content_margin_top">41.5dp</dimen>
<!-- height of the content margin on the bottom -->
- <dimen name="notification_content_margin_bottom">16dp</dimen>
+ <dimen name="notification_content_margin_bottom">18dp</dimen>
<!-- The height of the progress bar. -->
<dimen name="notification_progress_bar_height">15dp</dimen>
@@ -187,16 +187,16 @@
<dimen name="notification_progress_margin_top">8dp</dimen>
<!-- height of the notification header (for icon and package name) -->
- <dimen name="notification_header_height">48dp</dimen>
+ <dimen name="notification_header_height">54dp</dimen>
<!-- The height of the background for a notification header on a group -->
- <dimen name="notification_header_background_height">45.5dp</dimen>
+ <dimen name="notification_header_background_height">49.5dp</dimen>
<!-- The top padding for the notification header -->
- <dimen name="notification_header_padding_top">10dp</dimen>
+ <dimen name="notification_header_padding_top">14dp</dimen>
<!-- The bottom padding for the notification header -->
- <dimen name="notification_header_padding_bottom">11dp</dimen>
+ <dimen name="notification_header_padding_bottom">13dp</dimen>
<!-- The margin at the bottom of the notification header. -->
<dimen name="notification_header_margin_bottom">5dp</dimen>
@@ -266,6 +266,8 @@
<dimen name="alert_dialog_round_padding">27dip</dimen>
<!-- Dialog title height -->
<dimen name="alert_dialog_title_height">64dip</dimen>
+ <!-- Dialog button bar width -->
+ <dimen name="alert_dialog_button_bar_width">64dp</dimen>
<!-- Dialog button bar height -->
<dimen name="alert_dialog_button_bar_height">48dip</dimen>
<!-- Leanback dialog vertical margin -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d3533fe..373a656 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2852,9 +2852,18 @@
<public name="compileSdkVersion" />
<!-- @hide For use by platform and tools only. Developers should not specify this value. -->
<public name="compileSdkVersionCodename" />
+ <public name="screenReaderFocusable" />
+ <public name="buttonCornerRadius" />
+ <public name="versionCodeMajor" />
+ <public name="versionMajor" />
+ <!-- @hide @SystemApi -->
+ <public name="isVrOnly"/>
+ <public name="widgetFeatures" />
</public-group>
<public-group type="style" first-id="0x010302e0">
+ <public name="Widget.DeviceDefault.Button.Colored" />
+ <public name="Widget.DeviceDefault.Button.Borderless.Colored" />
</public-group>
<public-group type="id" first-id="0x01020044">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e4310e1..5ccaf5c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -471,6 +471,9 @@
<!-- label for item that generates a bug report in the phone options dialog -->
<string name="global_action_bug_report">Bug report</string>
+ <!-- label for item that logouts the current user -->
+ <string name="global_action_logout">End session</string>
+
<!-- Take bug report menu title [CHAR LIMIT=NONE] -->
<string name="bugreport_title">Take bug report</string>
<!-- Message in bugreport dialog describing what it does [CHAR LIMIT=NONE] -->
@@ -2853,7 +2856,7 @@
<string name="unsupported_display_size_show">Always show</string>
<!-- [CHAR LIMIT=200] Unsupported compile SDK dialog: message. Shown when an app may not be compatible with the device's current version of Android. -->
- <string name="unsupported_compile_sdk_message"><xliff:g id="app_name">%1$s</xliff:g> was built for preview version %2$s of the Android OS and may behave unexpectedly. An updated version of the app may be available.</string>
+ <string name="unsupported_compile_sdk_message"><xliff:g id="app_name">%1$s</xliff:g> was built for an incompatible version of the Android OS and may behave unexpectedly. An updated version of the app may be available.</string>
<!-- [CHAR LIMIT=50] Unsupported compile SDK dialog: check box label. -->
<string name="unsupported_compile_sdk_show">Always show</string>
<!-- [CHAR LIMIT=50] Unsupported compile SDK dialog: label for button to check for an app update. -->
@@ -4031,6 +4034,14 @@
shortcut enabled.-->
<string name="leave_accessibility_shortcut_on">Use Shortcut</string>
+ <!-- Title of Color Inversion feature shown in the warning dialog about the accessibility
+ shortcut. -->
+ <string name="color_inversion_feature_name">Color Inversion</string>
+
+ <!-- Title of Color Correction feature, which is mostly used to help users who are colorblind,
+ shown in the warning dialog about the accessibility shortcut. -->
+ <string name="color_correction_feature_name">Color Correction</string>
+
<!-- Text in toast to alert the user that the accessibility shortcut turned on an accessibility
service.-->
<string name="accessibility_shortcut_enabling_service">Accessibility Shortcut turned
@@ -4463,6 +4474,9 @@
<!-- Zen mode - name of default automatic calendar event-based rule. [CHAR LIMIT=40] -->
<string name="zen_mode_default_events_name">Event</string>
+ <!-- Zen mode - name of default automatic calendar time-based rule that is triggered every night (when sleeping). [CHAR LIMIT=40] -->
+ <string name="zen_mode_default_every_night_name">Sleeping</string>
+
<!-- Indication that the current volume and other effects (vibration) are being suppressed by a third party, such as a notification listener. [CHAR LIMIT=30] -->
<string name="muted_by">Muted by <xliff:g id="third_party">%1$s</xliff:g></string>
@@ -4476,7 +4490,9 @@
<string name="stk_cc_ussd_to_dial">USSD request is modified to DIAL request.</string>
<string name="stk_cc_ussd_to_ss">USSD request is modified to SS request.</string>
<string name="stk_cc_ussd_to_ussd">USSD request is modified to new USSD request.</string>
+ <string name="stk_cc_ussd_to_dial_video">USSD request is modified to Video DIAL request.</string>
<string name="stk_cc_ss_to_dial">SS request is modified to DIAL request.</string>
+ <string name="stk_cc_ss_to_dial_video">SS request is modified to Video DIAL request.</string>
<string name="stk_cc_ss_to_ussd">SS request is modified to USSD request.</string>
<string name="stk_cc_ss_to_ss">SS request is modified to new SS request.</string>
@@ -4753,5 +4769,8 @@
<string name="shortcut_restore_unknown_issue">Couldn\u2019t restore shortcut</string>
<!--Battery saver warning. STOPSHIP: Remove it eventually. -->
- <string name="battery_saver_warning" translatable="false">Battery saver activated.\n\nSee go/extreme-battery-saver.\n\nThis contains aggressive experimental changes for P and may affect background app behavior.\n</string>
+ <string name="battery_saver_warning" translatable="false">\"Extreme\" battery saver activated.\n\nSee the details at: go/extreme-battery-saver\n\nEBS aggressively throttles background apps and changes screen-off behavior.\n</string>
+
+ <!--Battery saver warning. STOPSHIP: Remove it eventually. -->
+ <string name="battery_saver_warning_title" translatable="false">Extreme battery saver</string>
</resources>
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 93a5264..189b3b7 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -37,6 +37,10 @@
<style name="Widget.DeviceDefault.Button.Small" parent="Widget.Material.Button.Small"/>
<style name="Widget.DeviceDefault.Button.Inset" parent="Widget.Material.Button.Inset"/>
<style name="Widget.DeviceDefault.Button.Toggle" parent="Widget.Material.Button.Toggle"/>
+ <style name="Widget.DeviceDefault.Button.Colored" parent="Widget.Material.Button.Colored">
+ <item name="textAppearance">?attr/textAppearanceButton</item>
+ <item name="textColor">@color/btn_colored_text_material</item>
+ </style>
<style name="Widget.DeviceDefault.TextView" parent="Widget.Material.TextView"/>
<style name="Widget.DeviceDefault.CheckedTextView" parent="Widget.Material.CheckedTextView"/>
<style name="Widget.DeviceDefault.AutoCompleteTextView" parent="Widget.Material.AutoCompleteTextView"/>
@@ -77,6 +81,15 @@
<style name="Widget.DeviceDefault.ActionButton.CloseMode" parent="Widget.Material.ActionButton.CloseMode"/>
<style name="Widget.DeviceDefault.ActionBar" parent="Widget.Material.ActionBar"/>
<style name="Widget.DeviceDefault.Button.Borderless" parent="Widget.Material.Button.Borderless"/>
+ <!-- Colored borderless ink button -->
+ <style name="Widget.DeviceDefault.Button.Borderless.Colored">
+ <item name="textAppearance">@style/TextAppearance.DeviceDefault.Widget.Button.Borderless.Colored</item>
+ </style>
+ <!-- Alert dialog button bar button -->
+ <style name="Widget.DeviceDefault.Button.ButtonBar.AlertDialog" parent="Widget.DeviceDefault.Button.Borderless.Colored">
+ <item name="minWidth">@dimen/alert_dialog_button_bar_width</item>
+ <item name="minHeight">@dimen/alert_dialog_button_bar_height</item>
+ </style>
<style name="Widget.DeviceDefault.Tab" parent="Widget.Material.Tab"/>
<style name="Widget.DeviceDefault.CalendarView" parent="Widget.Material.CalendarView"/>
<style name="Widget.DeviceDefault.DatePicker" parent="Widget.Material.DatePicker"/>
@@ -211,7 +224,10 @@
<style name="TextAppearance.DeviceDefault.SearchResult.Title" parent="TextAppearance.Material.SearchResult.Title"/>
<style name="TextAppearance.DeviceDefault.SearchResult.Subtitle" parent="TextAppearance.Material.SearchResult.Subtitle"/>
<style name="TextAppearance.DeviceDefault.Widget" parent="TextAppearance.Material.Widget"/>
- <style name="TextAppearance.DeviceDefault.Widget.Button" parent="TextAppearance.Material.Widget.Button"/>
+ <style name="TextAppearance.DeviceDefault.Widget.Button" parent="TextAppearance.Material.Widget.Button">
+ <item name="fontFamily">@string/config_fontFamilyButton</item>
+ <item name="textAllCaps">@bool/config_buttonTextAllCaps</item>
+ </style>
<style name="TextAppearance.DeviceDefault.Widget.IconMenu.Item" parent="TextAppearance.Material.Widget.IconMenu.Item"/>
<style name="TextAppearance.DeviceDefault.Widget.TabWidget" parent="TextAppearance.Material.Widget.TabWidget"/>
<style name="TextAppearance.DeviceDefault.Widget.TextView" parent="TextAppearance.Material.Widget.TextView"/>
@@ -220,6 +236,9 @@
<style name="TextAppearance.DeviceDefault.Widget.DropDownItem" parent="TextAppearance.Material.Widget.DropDownItem"/>
<style name="TextAppearance.DeviceDefault.Widget.TextView.SpinnerItem" parent="TextAppearance.Material.Widget.TextView.SpinnerItem"/>
<style name="TextAppearance.DeviceDefault.Widget.EditText" parent="TextAppearance.Material.Widget.EditText"/>
+ <style name="TextAppearance.DeviceDefault.Widget.Button.Borderless.Colored" parent="TextAppearance.DeviceDefault.Widget.Button">
+ <item name="textColor">@color/btn_colored_borderless_text_material</item>
+ </style>
<style name="TextAppearance.DeviceDefault.Widget.PopupMenu" parent="TextAppearance.Material.Widget.PopupMenu"/>
<style name="TextAppearance.DeviceDefault.Widget.PopupMenu.Large" parent="TextAppearance.Material.Widget.PopupMenu.Large"/>
<style name="TextAppearance.DeviceDefault.Widget.PopupMenu.Small" parent="TextAppearance.Material.Widget.PopupMenu.Small"/>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 2cd4dcb..def650a 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -561,7 +561,7 @@
<!-- Alert dialog button bar button -->
<style name="Widget.Material.Button.ButtonBar.AlertDialog" parent="Widget.Material.Button.Borderless.Colored">
- <item name="minWidth">64dp</item>
+ <item name="minWidth">@dimen/alert_dialog_button_bar_width</item>
<item name="minHeight">@dimen/alert_dialog_button_bar_height</item>
</style>
@@ -1304,7 +1304,7 @@
<item name="paddingBottom">@dimen/notification_header_padding_bottom</item>
<item name="layout_marginBottom">@dimen/notification_header_margin_bottom</item>
<item name="paddingStart">@dimen/notification_content_margin_start</item>
- <item name="paddingEnd">16dp</item>
+ <item name="paddingEnd">@dimen/notification_content_margin_end</item>
<item name="gravity">top</item>
</style>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a115816..f659360 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -391,6 +391,8 @@
<java-symbol type="integer" name="config_wifi_framework_min_tx_rate_for_staying_on_network" />
<java-symbol type="integer" name="config_wifi_framework_min_rx_rate_for_staying_on_network" />
+ <java-symbol type="integer" name="config_wifi_framework_soft_ap_timeout_delay" />
+
<java-symbol type="bool" name="config_wifi_framework_cellular_handover_enable_user_triggered_adjustment" />
<java-symbol type="integer" name="config_wifi_framework_associated_full_scan_tx_packet_threshold" />
<java-symbol type="integer" name="config_wifi_framework_associated_full_scan_rx_packet_threshold" />
@@ -459,6 +461,7 @@
<java-symbol type="bool" name="config_hasPermanentDpad" />
<java-symbol type="bool" name="config_useDefaultFocusHighlight" />
<java-symbol type="array" name="config_deviceSpecificSystemServices" />
+ <java-symbol type="string" name="config_deviceSpecificDevicePolicyManagerService" />
<java-symbol type="color" name="tab_indicator_text_v4" />
@@ -1045,9 +1048,11 @@
<java-symbol type="string" name="stk_cc_ss_to_dial" />
<java-symbol type="string" name="stk_cc_ss_to_ss" />
<java-symbol type="string" name="stk_cc_ss_to_ussd" />
+ <java-symbol type="string" name="stk_cc_ss_to_dial_video" />
<java-symbol type="string" name="stk_cc_ussd_to_dial" />
<java-symbol type="string" name="stk_cc_ussd_to_ss" />
<java-symbol type="string" name="stk_cc_ussd_to_ussd" />
+ <java-symbol type="string" name="stk_cc_ussd_to_dial_video" />
<java-symbol type="string" name="safe_media_volume_warning" />
<java-symbol type="string" name="media_route_status_scanning" />
<java-symbol type="string" name="media_route_status_connecting" />
@@ -1064,6 +1069,8 @@
<java-symbol type="string" name="action_bar_home_description_format" />
<java-symbol type="string" name="action_bar_home_subtitle_description_format" />
<java-symbol type="string" name="wireless_display_route_description" />
+ <java-symbol type="string" name="user_owner_label" />
+ <java-symbol type="string" name="managed_profile_label" />
<java-symbol type="string" name="managed_profile_label_badge" />
<java-symbol type="string" name="managed_profile_label_badge_2" />
<java-symbol type="string" name="managed_profile_label_badge_3" />
@@ -2259,6 +2266,7 @@
<java-symbol type="string" name="zen_mode_default_weeknights_name" />
<java-symbol type="string" name="zen_mode_default_weekends_name" />
<java-symbol type="string" name="zen_mode_default_events_name" />
+ <java-symbol type="string" name="zen_mode_default_every_night_name" />
<java-symbol type="array" name="config_system_condition_providers" />
<java-symbol type="string" name="muted_by" />
<java-symbol type="string" name="zen_mode_alarm" />
@@ -2908,6 +2916,8 @@
<java-symbol type="string" name="accessibility_shortcut_disabling_service" />
<java-symbol type="string" name="disable_accessibility_shortcut" />
<java-symbol type="string" name="leave_accessibility_shortcut_on" />
+ <java-symbol type="string" name="color_inversion_feature_name" />
+ <java-symbol type="string" name="color_correction_feature_name" />
<java-symbol type="string" name="config_defaultAccessibilityService" />
<!-- Accessibility Button -->
@@ -2929,8 +2939,8 @@
<!-- com.android.server.autofill -->
<java-symbol type="layout" name="autofill_save"/>
<java-symbol type="layout" name="autofill_dataset_picker"/>
- <java-symbol type="id" name="autofill_dataset_picker"/>
<java-symbol type="id" name="autofill_dataset_list"/>
+ <java-symbol type="id" name="autofill_dataset_picker"/>
<java-symbol type="id" name="autofill" />
<java-symbol type="id" name="autofill_save_custom_subtitle" />
<java-symbol type="id" name="autofill_save_icon" />
@@ -3158,4 +3168,9 @@
<java-symbol type="layout" name="unsupported_compile_sdk_dialog_content" />
<java-symbol type="string" name="unsupported_compile_sdk_message" />
<java-symbol type="string" name="unsupported_compile_sdk_check_update" />
+
+ <java-symbol type="string" name="battery_saver_warning_title" />
+
+ <java-symbol type="string" name="global_action_logout" />
+ <java-symbol type="drawable" name="ic_logout" />
</resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 68d5523..39310a8 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -69,12 +69,13 @@
<item name="textAppearanceSmallPopupMenu">@style/TextAppearance.DeviceDefault.Widget.PopupMenu.Small</item>
<!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonStyle">@style/Widget.DeviceDefault.Button</item>
<item name="buttonStyleSmall">@style/Widget.DeviceDefault.Button.Small</item>
<item name="buttonStyleInset">@style/Widget.DeviceDefault.Button.Inset</item>
-
<item name="buttonStyleToggle">@style/Widget.DeviceDefault.Button.Toggle</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<item name="switchStyle">@style/Widget.DeviceDefault.CompoundButton.Switch</item>
<item name="borderlessButtonStyle">@style/Widget.DeviceDefault.Button.Borderless</item>
@@ -219,6 +220,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar. This theme
@@ -232,6 +240,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
@@ -247,6 +262,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent
@@ -261,6 +283,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
@@ -273,8 +302,14 @@
<item name="buttonBarStyle">@style/DeviceDefault.ButtonBar.AlertDialog</item>
<item name="borderlessButtonStyle">@style/Widget.DeviceDefault.Button.Borderless.Small</item>
+ <!-- Text styles -->
<item name="textAppearance">@style/TextAppearance.DeviceDefault</item>
<item name="textAppearanceInverse">@style/TextAppearance.DeviceDefault.Inverse</item>
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Color palette -->
<item name="colorPrimary">@color/primary_device_default_dark</item>
@@ -297,6 +332,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
@@ -309,6 +351,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
@@ -322,6 +371,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -351,6 +407,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- DeviceDefault theme for a window without an action bar that will be displayed either
@@ -365,6 +428,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- DeviceDefault theme for a presentation window on a secondary display. -->
@@ -377,6 +447,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- DeviceDefault theme for panel windows. This removes all extraneous window
@@ -391,6 +468,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -404,6 +488,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -417,6 +508,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- DeviceDefault style for input methods, which is used by the
@@ -430,6 +528,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- DeviceDefault style for input methods, which is used by the
@@ -443,6 +548,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
@@ -456,6 +568,13 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<style name="Theme.DeviceDefault.SearchBar" parent="Theme.Material.SearchBar">
@@ -467,6 +586,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame">
@@ -478,6 +604,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
@@ -501,6 +634,7 @@
<item name="textAppearanceSmallPopupMenu">@style/TextAppearance.DeviceDefault.Widget.PopupMenu.Small</item>
<!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonStyle">@style/Widget.DeviceDefault.Light.Button</item>
<item name="buttonStyleSmall">@style/Widget.DeviceDefault.Light.Button.Small</item>
@@ -644,6 +778,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
@@ -656,6 +797,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
@@ -669,6 +817,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
@@ -684,6 +839,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent
@@ -698,6 +860,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
@@ -711,11 +880,15 @@
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarStyle">@style/DeviceDefault.Light.ButtonBar.AlertDialog</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<item name="borderlessButtonStyle">@style/Widget.DeviceDefault.Light.Button.Borderless.Small</item>
<item name="textAppearance">@style/TextAppearance.DeviceDefault</item>
<item name="textAppearanceInverse">@style/TextAppearance.DeviceDefault.Inverse</item>
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
<!-- Color palette -->
<item name="colorPrimary">@color/primary_device_default_light</item>
@@ -734,6 +907,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
@@ -746,6 +926,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
@@ -759,6 +946,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -798,6 +992,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- DeviceDefault light theme for a window without an action bar that will be displayed either
@@ -812,6 +1013,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- DeviceDefault light theme for a presentation window on a secondary display. -->
@@ -824,6 +1032,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- DeviceDefault light theme for panel windows. This removes all extraneous window
@@ -838,6 +1053,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert">
@@ -851,6 +1073,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Material.Light.SearchBar">
@@ -862,6 +1091,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<style name="Theme.DeviceDefault.Light.Voice" parent="Theme.Material.Light.Voice">
@@ -873,6 +1109,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- DeviceDefault theme for a window that should look like the Settings app. -->
@@ -882,6 +1125,7 @@
<item name="popupTheme">@style/ThemeOverlay.DeviceDefault.Popup.Light</item>
<!-- Color palette -->
+ <item name="colorBackground">@color/background_device_default_light</item>
<item name="colorPrimary">@color/primary_device_default_settings_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_settings_light</item>
<item name="colorSecondary">@color/secondary_device_default_settings_light</item>
@@ -896,6 +1140,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<!-- @hide DeviceDefault theme for a window that should use Settings theme colors
@@ -908,6 +1159,13 @@
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorControlNormal">?attr/textColorPrimary</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<style name="Theme.DeviceDefault.QuickSettings.Dialog" parent="Theme.DeviceDefault.Light.Dialog">
@@ -930,6 +1188,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.Material.Settings.Dialog">
@@ -942,6 +1207,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<style name="Theme.DeviceDefault.Settings.DialogWhenLarge" parent="Theme.Material.Settings.DialogWhenLarge">
@@ -954,6 +1226,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert">
@@ -966,6 +1245,13 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text styles -->
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
+ <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index c317121..9e6b1ab 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -103,6 +103,7 @@
<item name="buttonStyleSmall">@style/Widget.Material.Button.Small</item>
<item name="buttonStyleInset">@style/Widget.Material.Button.Inset</item>
<item name="buttonStyleToggle">@style/Widget.Material.Button.Toggle</item>
+ <item name="buttonCornerRadius">@dimen/control_corner_material</item>
<item name="switchStyle">@style/Widget.Material.CompoundButton.Switch</item>
<item name="mediaRouteButtonStyle">@style/Widget.Material.MediaRouteButton</item>
@@ -472,6 +473,7 @@
<item name="buttonStyleSmall">@style/Widget.Material.Light.Button.Small</item>
<item name="buttonStyleInset">@style/Widget.Material.Light.Button.Inset</item>
<item name="buttonStyleToggle">@style/Widget.Material.Light.Button.Toggle</item>
+ <item name="buttonCornerRadius">@dimen/control_corner_material</item>
<item name="switchStyle">@style/Widget.Material.Light.CompoundButton.Switch</item>
<item name="mediaRouteButtonStyle">@style/Widget.Material.Light.MediaRouteButton</item>
diff --git a/core/tests/BroadcastRadioTests/Android.mk b/core/tests/BroadcastRadioTests/Android.mk
index c409e3a..8df3827 100644
--- a/core/tests/BroadcastRadioTests/Android.mk
+++ b/core/tests/BroadcastRadioTests/Android.mk
@@ -26,6 +26,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test testng
+LOCAL_JAVA_LIBRARIES := android.test.base
+
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index f2eb872..47990a1 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -30,6 +30,7 @@
LOCAL_JACK_FLAGS := --multi-dex native
LOCAL_AAPT_FLAGS = -0 dat -0 gld -c fa
LOCAL_STATIC_JAVA_LIBRARIES := \
+ frameworks-base-testutils \
core-tests-support \
android-common \
frameworks-core-util-lib \
@@ -44,7 +45,14 @@
truth-prebuilt \
print-test-util-lib
-LOCAL_JAVA_LIBRARIES := android.test.runner conscrypt telephony-common org.apache.http.legacy
+LOCAL_JAVA_LIBRARIES := \
+ android.test.runner \
+ conscrypt \
+ telephony-common \
+ org.apache.http.legacy \
+ android.test.base \
+ android.test.mock \
+
LOCAL_PACKAGE_NAME := FrameworksCoreTests
LOCAL_COMPATIBILITY_SUITE := device-tests
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 51bfc20..3f2a46a 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -68,6 +68,7 @@
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SMS"/>
<uses-permission android:name="android.permission.TEST_GRANTED" />
+ <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
<uses-permission android:name="com.google.android.googleapps.permission.ACCESS_GOOGLE_PASSWORD" />
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" />
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.ALL_SERVICES" />
diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml
index 23d70b8..970a0f0 100644
--- a/core/tests/coretests/AndroidTest.xml
+++ b/core/tests/coretests/AndroidTest.xml
@@ -16,6 +16,7 @@
<configuration description="Runs Frameworks Core Tests.">
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="test-file-name" value="FrameworksCoreTests.apk" />
+ <option name="test-file-name" value="BstatsTestApp.apk" />
</target_preparer>
<option name="test-suite-tag" value="apct" />
diff --git a/core/tests/coretests/BstatsTestApp/Android.mk b/core/tests/coretests/BstatsTestApp/Android.mk
new file mode 100644
index 0000000..6280257
--- /dev/null
+++ b/core/tests/coretests/BstatsTestApp/Android.mk
@@ -0,0 +1,32 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+LOCAL_STATIC_JAVA_LIBRARIES := coretests-aidl
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := BstatsTestApp
+LOCAL_CERTIFICATE := platform
+LOCAL_DEX_PREOPT := false
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/core/tests/coretests/BstatsTestApp/AndroidManifest.xml b/core/tests/coretests/BstatsTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..0cb5498
--- /dev/null
+++ b/core/tests/coretests/BstatsTestApp/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.coretests.apps.bstatstestapp">
+
+ <application>
+ <activity android:name=".TestActivity"
+ android:exported="true" />
+ <service android:name=".IsolatedTestService"
+ android:exported="true"
+ android:isolatedProcess="true" />
+ </application>
+
+</manifest>
\ No newline at end of file
diff --git a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/IsolatedTestService.java b/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/IsolatedTestService.java
new file mode 100644
index 0000000..1f5f397
--- /dev/null
+++ b/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/IsolatedTestService.java
@@ -0,0 +1,60 @@
+/*
+ * 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.coretests.apps.bstatstestapp;
+
+import com.android.frameworks.coretests.aidl.ICmdReceiver;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.SystemClock;
+import android.util.Log;
+
+public class IsolatedTestService extends Service {
+ private static final String TAG = IsolatedTestService.class.getName();
+
+ @Override
+ public void onCreate() {
+ Log.d(TAG, "onCreate called. myUid=" + Process.myUid());
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mReceiver.asBinder();
+ }
+
+ private ICmdReceiver mReceiver = new ICmdReceiver.Stub() {
+ @Override
+ public void doSomeWork(int durationMs) {
+ final long endTime = SystemClock.uptimeMillis() + durationMs;
+ double x;
+ double y;
+ double z;
+ while (SystemClock.uptimeMillis() <= endTime) {
+ x = 0.02;
+ x *= 1000;
+ y = x % 5;
+ z = Math.sqrt(y / 100);
+ }
+ };
+
+ @Override
+ public void finishHost() {
+ stopSelf();
+ }
+ };
+}
diff --git a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestActivity.java b/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestActivity.java
new file mode 100644
index 0000000..87b14d9
--- /dev/null
+++ b/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestActivity.java
@@ -0,0 +1,83 @@
+/*
+ * 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.coretests.apps.bstatstestapp;
+
+import com.android.frameworks.coretests.aidl.ICmdCallback;
+import com.android.frameworks.coretests.aidl.ICmdReceiver;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Log;
+
+public class TestActivity extends Activity {
+ private static final String TAG = TestActivity.class.getName();
+
+ private static final String EXTRA_KEY_CMD_RECEIVER = "cmd_receiver";
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ Log.d(TAG, "onCreate called");
+ notifyActivityLaunched();
+ }
+
+ private void notifyActivityLaunched() {
+ if (getIntent() == null) {
+ return;
+ }
+
+ final Bundle extras = getIntent().getExtras();
+ if (extras == null) {
+ return;
+ }
+ final ICmdCallback callback = ICmdCallback.Stub.asInterface(
+ extras.getBinder(EXTRA_KEY_CMD_RECEIVER));
+ try {
+ callback.onActivityLaunched(mReceiver.asBinder());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error occured while notifying the test: " + e);
+ }
+ }
+
+ @Override
+ public void finish() {
+ super.finish();
+ Log.d(TAG, "finish called");
+ }
+
+ private ICmdReceiver mReceiver = new ICmdReceiver.Stub() {
+ @Override
+ public void doSomeWork(int durationMs) {
+ final long endTime = SystemClock.uptimeMillis() + durationMs;
+ double x;
+ double y;
+ double z;
+ while (SystemClock.uptimeMillis() <= endTime) {
+ x = 0.02;
+ x *= 1000;
+ y = x % 5;
+ z = Math.sqrt(y / 100);
+ }
+ };
+
+ @Override
+ public void finishHost() {
+ finish();
+ }
+ };
+}
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/ICmdCallback.aidl
similarity index 71%
rename from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
rename to core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/ICmdCallback.aidl
index 4ccdea5..53a181a 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/ICmdCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,11 +14,8 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+package com.android.frameworks.coretests.aidl;
-import android.telephony.SubscriptionInfo;
-
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
-}
-
+interface ICmdCallback {
+ void onActivityLaunched(IBinder receiver);
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/ICmdReceiver.aidl
similarity index 71%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/ICmdReceiver.aidl
index 4ccdea5..c406570 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/ICmdReceiver.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,11 +14,9 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+package com.android.frameworks.coretests.aidl;
-import android.telephony.SubscriptionInfo;
-
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
-}
-
+interface ICmdReceiver {
+ void doSomeWork(int durationMs);
+ void finishHost();
+}
\ No newline at end of file
diff --git a/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttf b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttf
new file mode 100644
index 0000000..1bad6fe
--- /dev/null
+++ b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttf
Binary files differ
diff --git a/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx
new file mode 100644
index 0000000..0cf0f79
--- /dev/null
+++ b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="0em"/>
+ <GlyphID id="2" name="1em"/>
+ <GlyphID id="3" name="3em"/>
+ <GlyphID id="4" name="5em"/>
+ <GlyphID id="5" name="7em"/>
+ <GlyphID id="6" name="10em"/>
+ <GlyphID id="7" name="50em"/>
+ <GlyphID id="8" name="100em"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="100"/>
+ <created value="Fri Mar 17 07:26:00 2017"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="50" lsb="0"/>
+ <mtx name="0em" width="0" lsb="0"/>
+ <mtx name="1em" width="100" lsb="0"/>
+ <mtx name="3em" width="300" lsb="0"/>
+ <mtx name="5em" width="500" lsb="0"/>
+ <mtx name="7em" width="700" lsb="0"/>
+ <mtx name="10em" width="1000" lsb="0"/>
+ <mtx name="50em" width="5000" lsb="0"/>
+ <mtx name="100em" width="10000" lsb="0"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_12 format="12" reserved="0" length="6" nGroups="1" platformID="3" platEncID="10" language="0">
+ <map code="0x0020" name="10em" />
+ <map code="0x002e" name="10em" /> <!-- . -->
+ <map code="0x0043" name="100em" /> <!-- C -->
+ <map code="0x0049" name="1em" /> <!-- I -->
+ <map code="0x004c" name="50em" /> <!-- L -->
+ <map code="0x0056" name="5em" /> <!-- V -->
+ <map code="0x0058" name="10em" /> <!-- X -->
+ <map code="0x005f" name="0em" /> <!-- _ -->
+ <map code="0xfffd" name="7em" /> <!-- REPLACEMENT CHAR -->
+ <map code="0x10331" name="10em" />
+ </cmap_format_12>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="0em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="5em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="7em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="10em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="50em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="100em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Font for StaticLayoutLineBreakingTest
+ </namerecord>
+ <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Font for StaticLayoutLineBreakingTest
+ </namerecord>
+ <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ SampleFont-Regular
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFont-Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+</ttFont>
diff --git a/core/tests/coretests/res/xml/ime_meta_vr_only.xml b/core/tests/coretests/res/xml/ime_meta_vr_only.xml
new file mode 100644
index 0000000..653a8ff
--- /dev/null
+++ b/core/tests/coretests/res/xml/ime_meta_vr_only.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ 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.
+-->
+
+<input-method
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:settingsActivity="com.android.inputmethod.latin.settings.SettingsActivity"
+ android:isVrOnly="true">
+</input-method>
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index bec862a..c14dc90 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -19,12 +19,17 @@
import static com.android.internal.util.NotificationColorUtil.satisfiesTextContrast;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.content.Intent;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Icon;
import android.media.session.MediaSession;
import android.os.Parcel;
+import android.os.Parcelable;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -142,6 +147,36 @@
}
@Test
+ public void largeIconMultipleReferences_keptAfterParcelling() {
+ Icon originalIcon = Icon.createWithBitmap(BitmapFactory.decodeResource(
+ mContext.getResources(), com.android.frameworks.coretests.R.drawable.test128x96));
+
+ Notification n = new Notification.Builder(mContext).setLargeIcon(originalIcon).build();
+ assertSame(n.getLargeIcon(), originalIcon);
+
+ Notification q = writeAndReadParcelable(n);
+ assertNotSame(q.getLargeIcon(), n.getLargeIcon());
+
+ assertTrue(q.getLargeIcon().getBitmap().sameAs(n.getLargeIcon().getBitmap()));
+ assertSame(q.getLargeIcon(), q.extras.getParcelable(Notification.EXTRA_LARGE_ICON));
+ }
+
+ @Test
+ public void largeIconReferenceInExtrasOnly_keptAfterParcelling() {
+ Icon originalIcon = Icon.createWithBitmap(BitmapFactory.decodeResource(
+ mContext.getResources(), com.android.frameworks.coretests.R.drawable.test128x96));
+
+ Notification n = new Notification.Builder(mContext).build();
+ n.extras.putParcelable(Notification.EXTRA_LARGE_ICON, originalIcon);
+ assertSame(n.getLargeIcon(), null);
+
+ Notification q = writeAndReadParcelable(n);
+ assertSame(q.getLargeIcon(), null);
+ assertTrue(((Icon) q.extras.getParcelable(Notification.EXTRA_LARGE_ICON)).getBitmap()
+ .sameAs(originalIcon.getBitmap()));
+ }
+
+ @Test
public void allPendingIntents_recollectedAfterReusingBuilder() {
PendingIntent intent1 = PendingIntent.getActivity(mContext, 0, new Intent("test1"), 0);
PendingIntent intent2 = PendingIntent.getActivity(mContext, 0, new Intent("test2"), 0);
@@ -187,4 +222,15 @@
.setContentText("Text")
.setStyle(new Notification.MediaStyle().setMediaSession(session.getSessionToken()));
}
+
+ /**
+ * Writes an arbitrary {@link Parcelable} into a {@link Parcel} using its writeToParcel
+ * method before reading it out again to check that it was sent properly.
+ */
+ private static <T extends Parcelable> T writeAndReadParcelable(T original) {
+ Parcel p = Parcel.obtain();
+ p.writeParcelable(original, /* flags */ 0);
+ p.setDataPosition(0);
+ return p.readParcelable(/* classLoader */ null);
+ }
}
diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
new file mode 100644
index 0000000..b1f8552
--- /dev/null
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.ClientTransactionHandler;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class ClientTransactionTests {
+
+ @Test
+ public void testPreExecute() {
+ ClientTransactionItem callback1 = mock(ClientTransactionItem.class);
+ ClientTransactionItem callback2 = mock(ClientTransactionItem.class);
+ ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class);
+ ClientTransactionHandler clientTransactionHandler = mock(ClientTransactionHandler.class);
+ IBinder token = mock(IBinder.class);
+
+ ClientTransaction transaction = ClientTransaction.obtain(null /* client */,
+ token /* activityToken */);
+ transaction.addCallback(callback1);
+ transaction.addCallback(callback2);
+ transaction.setLifecycleStateRequest(stateRequest);
+
+ transaction.preExecute(clientTransactionHandler);
+
+ verify(callback1, times(1)).preExecute(clientTransactionHandler, token);
+ verify(callback2, times(1)).preExecute(clientTransactionHandler, token);
+ verify(stateRequest, times(1)).preExecute(clientTransactionHandler, token);
+ }
+}
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
new file mode 100644
index 0000000..aefc47e
--- /dev/null
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import static android.app.servertransaction.TestUtils.config;
+import static android.app.servertransaction.TestUtils.referrerIntentList;
+import static android.app.servertransaction.TestUtils.resultInfoList;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class ObjectPoolTests {
+
+ // 1. Check if two obtained objects from pool are not the same.
+ // 2. Check if the state of the object is cleared after recycling.
+ // 3. Check if the same object is obtained from pool after recycling.
+
+ @Test
+ public void testRecycleActivityConfigurationChangeItem() {
+ ActivityConfigurationChangeItem emptyItem = ActivityConfigurationChangeItem.obtain(null);
+ ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain(config());
+ assertNotSame(item, emptyItem);
+ assertFalse(item.equals(emptyItem));
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ ActivityConfigurationChangeItem item2 = ActivityConfigurationChangeItem.obtain(config());
+ assertSame(item, item2);
+ assertFalse(item2.equals(emptyItem));
+ }
+
+ @Test
+ public void testRecycleActivityResultItem() {
+ ActivityResultItem emptyItem = ActivityResultItem.obtain(null);
+ ActivityResultItem item = ActivityResultItem.obtain(resultInfoList());
+ assertNotSame(item, emptyItem);
+ assertFalse(item.equals(emptyItem));
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ ActivityResultItem item2 = ActivityResultItem.obtain(resultInfoList());
+ assertSame(item, item2);
+ assertFalse(item2.equals(emptyItem));
+ }
+
+ @Test
+ public void testRecycleConfigurationChangeItem() {
+ ConfigurationChangeItem emptyItem = ConfigurationChangeItem.obtain(null);
+ ConfigurationChangeItem item = ConfigurationChangeItem.obtain(config());
+ assertNotSame(item, emptyItem);
+ assertFalse(item.equals(emptyItem));
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ ConfigurationChangeItem item2 = ConfigurationChangeItem.obtain(config());
+ assertSame(item, item2);
+ assertFalse(item2.equals(emptyItem));
+ }
+
+ @Test
+ public void testRecycleDestroyActivityItem() {
+ DestroyActivityItem emptyItem = DestroyActivityItem.obtain(false, 0);
+ DestroyActivityItem item = DestroyActivityItem.obtain(true, 117);
+ assertNotSame(item, emptyItem);
+ assertFalse(item.equals(emptyItem));
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ DestroyActivityItem item2 = DestroyActivityItem.obtain(true, 14);
+ assertSame(item, item2);
+ assertFalse(item2.equals(emptyItem));
+ }
+
+ @Test
+ public void testRecycleLaunchActivityItem() {
+ Intent intent = new Intent("action");
+ int ident = 57;
+ ActivityInfo activityInfo = new ActivityInfo();
+ activityInfo.flags = 42;
+ activityInfo.maxAspectRatio = 2.4f;
+ activityInfo.launchToken = "token";
+ activityInfo.applicationInfo = new ApplicationInfo();
+ activityInfo.packageName = "packageName";
+ activityInfo.name = "name";
+ Configuration overrideConfig = new Configuration();
+ overrideConfig.assetsSeq = 5;
+ CompatibilityInfo compat = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
+ String referrer = "referrer";
+ int procState = 4;
+ Bundle bundle = new Bundle();
+ bundle.putString("key", "value");
+ PersistableBundle persistableBundle = new PersistableBundle();
+ persistableBundle.putInt("k", 4);
+
+ LaunchActivityItem emptyItem = LaunchActivityItem.obtain(null, 0, null, null, null, null,
+ null, null, 0, null, null, null, null, false, null);
+ LaunchActivityItem item = LaunchActivityItem.obtain(intent, ident, activityInfo,
+ config(), overrideConfig, compat, referrer, null /* voiceInteractor */,
+ procState, bundle, persistableBundle, resultInfoList(), referrerIntentList(),
+ true /* isForward */, null /* profilerInfo */);
+ assertNotSame(item, emptyItem);
+ assertFalse(item.equals(emptyItem));
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ LaunchActivityItem item2 = LaunchActivityItem.obtain(intent, ident, activityInfo,
+ config(), overrideConfig, compat, referrer, null /* voiceInteractor */,
+ procState, bundle, persistableBundle, resultInfoList(), referrerIntentList(),
+ true /* isForward */, null /* profilerInfo */);
+ assertSame(item, item2);
+ assertFalse(item2.equals(emptyItem));
+ }
+
+ @Test
+ public void testRecycleMoveToDisplayItem() {
+ MoveToDisplayItem emptyItem = MoveToDisplayItem.obtain(0, null);
+ MoveToDisplayItem item = MoveToDisplayItem.obtain(4, config());
+ assertNotSame(item, emptyItem);
+ assertFalse(item.equals(emptyItem));
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ MoveToDisplayItem item2 = MoveToDisplayItem.obtain(3, config());
+ assertSame(item, item2);
+ assertFalse(item2.equals(emptyItem));
+ }
+
+ @Test
+ public void testRecycleMultiWindowModeChangeItem() {
+ MultiWindowModeChangeItem emptyItem = MultiWindowModeChangeItem.obtain(false, null);
+ MultiWindowModeChangeItem item = MultiWindowModeChangeItem.obtain(true, config());
+ assertNotSame(item, emptyItem);
+ assertFalse(item.equals(emptyItem));
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ MultiWindowModeChangeItem item2 = MultiWindowModeChangeItem.obtain(true, config());
+ assertSame(item, item2);
+ assertFalse(item2.equals(emptyItem));
+ }
+
+ @Test
+ public void testRecycleNewIntentItem() {
+ NewIntentItem emptyItem = NewIntentItem.obtain(null, false);
+ NewIntentItem item = NewIntentItem.obtain(referrerIntentList(), true);
+ assertNotSame(item, emptyItem);
+ assertFalse(item.equals(emptyItem));
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ NewIntentItem item2 = NewIntentItem.obtain(referrerIntentList(), true);
+ assertSame(item, item2);
+ assertFalse(item2.equals(emptyItem));
+ }
+
+ @Test
+ public void testRecyclePauseActivityItemItem() {
+ PauseActivityItem emptyItem = PauseActivityItem.obtain(false, false, 0, false);
+ PauseActivityItem item = PauseActivityItem.obtain(true, true, 5, true);
+ assertNotSame(item, emptyItem);
+ assertFalse(item.equals(emptyItem));
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ PauseActivityItem item2 = PauseActivityItem.obtain(true, false, 5, true);
+ assertSame(item, item2);
+ assertFalse(item2.equals(emptyItem));
+ }
+
+ @Test
+ public void testRecyclePipModeChangeItem() {
+ PipModeChangeItem emptyItem = PipModeChangeItem.obtain(false, null);
+ PipModeChangeItem item = PipModeChangeItem.obtain(true, config());
+ assertNotSame(item, emptyItem);
+ assertFalse(item.equals(emptyItem));
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ PipModeChangeItem item2 = PipModeChangeItem.obtain(true, config());
+ assertSame(item, item2);
+ assertFalse(item2.equals(emptyItem));
+ }
+
+ @Test
+ public void testRecycleResumeActivityItem() {
+ ResumeActivityItem emptyItem = ResumeActivityItem.obtain(false);
+ ResumeActivityItem item = ResumeActivityItem.obtain(3, true);
+ assertNotSame(item, emptyItem);
+ assertFalse(item.equals(emptyItem));
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ ResumeActivityItem item2 = ResumeActivityItem.obtain(2, true);
+ assertSame(item, item2);
+ assertFalse(item2.equals(emptyItem));
+ }
+
+ @Test
+ public void testRecycleStopItem() {
+ StopActivityItem emptyItem = StopActivityItem.obtain(false, 0);
+ StopActivityItem item = StopActivityItem.obtain(true, 4);
+ assertNotSame(item, emptyItem);
+ assertFalse(item.equals(emptyItem));
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ StopActivityItem item2 = StopActivityItem.obtain(true, 3);
+ assertSame(item, item2);
+ assertFalse(item2.equals(emptyItem));
+ }
+
+ @Test
+ public void testRecycleWindowVisibleItem() {
+ WindowVisibilityItem emptyItem = WindowVisibilityItem.obtain(false);
+ WindowVisibilityItem item = WindowVisibilityItem.obtain(true);
+ assertNotSame(item, emptyItem);
+ assertFalse(item.equals(emptyItem));
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ WindowVisibilityItem item2 = WindowVisibilityItem.obtain(true);
+ assertSame(item, item2);
+ assertFalse(item2.equals(emptyItem));
+ }
+
+ @Test
+ public void testRecycleClientTransaction() {
+ ClientTransaction emptyItem = ClientTransaction.obtain(null, null);
+ ClientTransaction item = ClientTransaction.obtain(null, new Binder());
+ assertNotSame(item, emptyItem);
+ assertFalse(item.equals(emptyItem));
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ ClientTransaction item2 = ClientTransaction.obtain(null, new Binder());
+ assertSame(item, item2);
+ assertFalse(item2.equals(emptyItem));
+ }
+}
diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
new file mode 100644
index 0000000..e923516
--- /dev/null
+++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+
+import android.app.ResultInfo;
+import android.content.Intent;
+import android.content.res.Configuration;
+
+import com.android.internal.content.ReferrerIntent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class TestUtils {
+
+ static Configuration config() {
+ Configuration config = new Configuration();
+ config.densityDpi = 10;
+ config.fontScale = 0.3f;
+ config.screenHeightDp = 15;
+ config.orientation = ORIENTATION_LANDSCAPE;
+ return config;
+ }
+
+ static List<ResultInfo> resultInfoList() {
+ String resultWho1 = "resultWho1";
+ int requestCode1 = 7;
+ int resultCode1 = 4;
+ Intent data1 = new Intent("action1");
+ ResultInfo resultInfo1 = new ResultInfo(resultWho1, requestCode1, resultCode1, data1);
+
+ String resultWho2 = "resultWho2";
+ int requestCode2 = 8;
+ int resultCode2 = 6;
+ Intent data2 = new Intent("action2");
+ ResultInfo resultInfo2 = new ResultInfo(resultWho2, requestCode2, resultCode2, data2);
+
+ List<ResultInfo> resultInfoList = new ArrayList<>();
+ resultInfoList.add(resultInfo1);
+ resultInfoList.add(resultInfo2);
+
+ return resultInfoList;
+ }
+
+ static List<ReferrerIntent> referrerIntentList() {
+ Intent intent1 = new Intent("action1");
+ ReferrerIntent referrerIntent1 = new ReferrerIntent(intent1, "referrer1");
+
+ Intent intent2 = new Intent("action2");
+ ReferrerIntent referrerIntent2 = new ReferrerIntent(intent2, "referrer2");
+
+ List<ReferrerIntent> referrerIntents = new ArrayList<>();
+ referrerIntents.add(referrerIntent1);
+ referrerIntents.add(referrerIntent2);
+
+ return referrerIntents;
+ }
+}
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
new file mode 100644
index 0000000..e575650
--- /dev/null
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_DESTROY;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_RESTART;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_START;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
+import static android.app.servertransaction.ActivityLifecycleItem.PRE_ON_CREATE;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityThread.ActivityClientRecord;
+import android.app.ClientTransactionHandler;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+
+import java.util.ArrayList;
+
+/** Test {@link TransactionExecutor} logic. */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class TransactionExecutorTests {
+
+ private TransactionExecutor mExecutor;
+ private ClientTransactionHandler mTransactionHandler;
+ private ActivityClientRecord mClientRecord;
+
+ @Before
+ public void setUp() throws Exception {
+ mTransactionHandler = mock(ClientTransactionHandler.class);
+
+ mClientRecord = new ActivityClientRecord();
+ when(mTransactionHandler.getActivityClient(any())).thenReturn(mClientRecord);
+
+ mExecutor = spy(new TransactionExecutor(mTransactionHandler));
+ }
+
+ @Test
+ public void testLifecycleFromPreOnCreate() {
+ mClientRecord.setState(PRE_ON_CREATE);
+ assertArrayEquals(new int[] {}, path(PRE_ON_CREATE));
+ assertArrayEquals(new int[] {ON_CREATE}, path(ON_CREATE));
+ assertArrayEquals(new int[] {ON_CREATE, ON_START}, path(ON_START));
+ assertArrayEquals(new int[] {ON_CREATE, ON_START, ON_RESUME}, path(ON_RESUME));
+ assertArrayEquals(new int[] {ON_CREATE, ON_START, ON_RESUME, ON_PAUSE}, path(ON_PAUSE));
+ assertArrayEquals(new int[] {ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP},
+ path(ON_STOP));
+ assertArrayEquals(new int[] {ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY},
+ path(ON_DESTROY));
+ }
+
+ @Test
+ public void testLifecycleFromOnCreate() {
+ mClientRecord.setState(ON_CREATE);
+ assertArrayEquals(new int[] {}, path(ON_CREATE));
+ assertArrayEquals(new int[] {ON_START}, path(ON_START));
+ assertArrayEquals(new int[] {ON_START, ON_RESUME}, path(ON_RESUME));
+ assertArrayEquals(new int[] {ON_START, ON_RESUME, ON_PAUSE}, path(ON_PAUSE));
+ assertArrayEquals(new int[] {ON_START, ON_RESUME, ON_PAUSE, ON_STOP}, path(ON_STOP));
+ assertArrayEquals(new int[] {ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY},
+ path(ON_DESTROY));
+ }
+
+ @Test
+ public void testLifecycleFromOnStart() {
+ mClientRecord.setState(ON_START);
+ assertArrayEquals(new int[] {ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY, ON_CREATE},
+ path(ON_CREATE));
+ assertArrayEquals(new int[] {}, path(ON_START));
+ assertArrayEquals(new int[] {ON_RESUME}, path(ON_RESUME));
+ assertArrayEquals(new int[] {ON_RESUME, ON_PAUSE}, path(ON_PAUSE));
+ assertArrayEquals(new int[] {ON_RESUME, ON_PAUSE, ON_STOP}, path(ON_STOP));
+ assertArrayEquals(new int[] {ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY}, path(ON_DESTROY));
+ }
+
+ @Test
+ public void testLifecycleFromOnResume() {
+ mClientRecord.setState(ON_RESUME);
+ assertArrayEquals(new int[] {ON_PAUSE, ON_STOP, ON_DESTROY, ON_CREATE}, path(ON_CREATE));
+ assertArrayEquals(new int[] {ON_PAUSE, ON_STOP, ON_RESTART, ON_START}, path(ON_START));
+ assertArrayEquals(new int[] {}, path(ON_RESUME));
+ assertArrayEquals(new int[] {ON_PAUSE}, path(ON_PAUSE));
+ assertArrayEquals(new int[] {ON_PAUSE, ON_STOP}, path(ON_STOP));
+ assertArrayEquals(new int[] {ON_PAUSE, ON_STOP, ON_DESTROY}, path(ON_DESTROY));
+ }
+
+ @Test
+ public void testLifecycleFromOnPause() {
+ mClientRecord.setState(ON_PAUSE);
+ assertArrayEquals(new int[] {ON_STOP, ON_DESTROY, ON_CREATE}, path(ON_CREATE));
+ assertArrayEquals(new int[] {ON_STOP, ON_RESTART, ON_START}, path(ON_START));
+ assertArrayEquals(new int[] {ON_RESUME}, path(ON_RESUME));
+ assertArrayEquals(new int[] {}, path(ON_PAUSE));
+ assertArrayEquals(new int[] {ON_STOP}, path(ON_STOP));
+ assertArrayEquals(new int[] {ON_STOP, ON_DESTROY}, path(ON_DESTROY));
+ }
+
+ @Test
+ public void testLifecycleFromOnStop() {
+ mClientRecord.setState(ON_STOP);
+ assertArrayEquals(new int[] {ON_DESTROY, ON_CREATE}, path(ON_CREATE));
+ assertArrayEquals(new int[] {ON_RESTART, ON_START}, path(ON_START));
+ assertArrayEquals(new int[] {ON_RESTART, ON_START, ON_RESUME}, path(ON_RESUME));
+ assertArrayEquals(new int[] {ON_RESTART, ON_START, ON_RESUME, ON_PAUSE}, path(ON_PAUSE));
+ assertArrayEquals(new int[] {}, path(ON_STOP));
+ assertArrayEquals(new int[] {ON_DESTROY}, path(ON_DESTROY));
+ }
+
+ @Test
+ public void testLifecycleFromOnDestroy() {
+ mClientRecord.setState(ON_DESTROY);
+ assertArrayEquals(new int[] {ON_CREATE}, path(ON_CREATE));
+ assertArrayEquals(new int[] {ON_CREATE, ON_START}, path(ON_START));
+ assertArrayEquals(new int[] {ON_CREATE, ON_START, ON_RESUME}, path(ON_RESUME));
+ assertArrayEquals(new int[] {ON_CREATE, ON_START, ON_RESUME, ON_PAUSE}, path(ON_PAUSE));
+ assertArrayEquals(new int[] {ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP},
+ path(ON_STOP));
+ assertArrayEquals(new int[] {}, path(ON_DESTROY));
+ }
+
+ @Test
+ public void testLifecycleExcludeLastItem() {
+ mClientRecord.setState(PRE_ON_CREATE);
+ assertArrayEquals(new int[] {}, pathExcludeLast(PRE_ON_CREATE));
+ assertArrayEquals(new int[] {}, pathExcludeLast(ON_CREATE));
+ assertArrayEquals(new int[] {ON_CREATE}, pathExcludeLast(ON_START));
+ assertArrayEquals(new int[] {ON_CREATE, ON_START}, pathExcludeLast(ON_RESUME));
+ assertArrayEquals(new int[] {ON_CREATE, ON_START, ON_RESUME}, pathExcludeLast(ON_PAUSE));
+ assertArrayEquals(new int[] {ON_CREATE, ON_START, ON_RESUME, ON_PAUSE},
+ pathExcludeLast(ON_STOP));
+ assertArrayEquals(new int[] {ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP},
+ pathExcludeLast(ON_DESTROY));
+ }
+
+ @Test
+ public void testTransactionResolution() {
+ ClientTransactionItem callback1 = mock(ClientTransactionItem.class);
+ ClientTransactionItem callback2 = mock(ClientTransactionItem.class);
+ ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class);
+ IBinder token = mock(IBinder.class);
+
+ ClientTransaction transaction = ClientTransaction.obtain(null /* client */,
+ token /* activityToken */);
+ transaction.addCallback(callback1);
+ transaction.addCallback(callback2);
+ transaction.setLifecycleStateRequest(stateRequest);
+
+ transaction.preExecute(mTransactionHandler);
+ mExecutor.execute(transaction);
+
+ InOrder inOrder = inOrder(mTransactionHandler, callback1, callback2, stateRequest);
+ inOrder.verify(callback1, times(1)).execute(eq(mTransactionHandler), eq(token), any());
+ inOrder.verify(callback2, times(1)).execute(eq(mTransactionHandler), eq(token), any());
+ inOrder.verify(stateRequest, times(1)).execute(eq(mTransactionHandler), eq(token), any());
+ }
+
+ @Test
+ public void testRequiredStateResolution() {
+ ActivityResultItem activityResultItem = ActivityResultItem.obtain(new ArrayList<>());
+
+ IBinder token = mock(IBinder.class);
+ ClientTransaction transaction = ClientTransaction.obtain(null /* client */,
+ token /* activityToken */);
+ transaction.addCallback(activityResultItem);
+
+ mExecutor.executeCallbacks(transaction);
+
+ verify(mExecutor, times(1)).cycleToPath(eq(mClientRecord), eq(ON_PAUSE));
+ }
+
+ private int[] path(int finish) {
+ mExecutor.initLifecyclePath(mClientRecord.getLifecycleState(), finish,
+ false /* excludeLastState */);
+ return mExecutor.getLifecycleSequence();
+ }
+
+ private int[] pathExcludeLast(int finish) {
+ mExecutor.initLifecyclePath(mClientRecord.getLifecycleState(), finish,
+ true /* excludeLastState */);
+ return mExecutor.getLifecycleSequence();
+ }
+}
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
new file mode 100644
index 0000000..4b1f2da
--- /dev/null
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -0,0 +1,604 @@
+/*
+ * Copyright 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 android.app.servertransaction;
+
+import static android.app.servertransaction.TestUtils.config;
+import static android.app.servertransaction.TestUtils.referrerIntentList;
+import static android.app.servertransaction.TestUtils.resultInfoList;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import android.app.IApplicationThread;
+import android.app.IInstrumentationWatcher;
+import android.app.IUiAutomationConnection;
+import android.app.ProfilerInfo;
+import android.app.ResultInfo;
+import android.content.ComponentName;
+import android.content.IIntentReceiver;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ServiceInfo;
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+import android.os.PersistableBundle;
+import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.content.ReferrerIntent;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.Map;
+
+/** Test parcelling and unparcelling of transactions and transaction items. */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class TransactionParcelTests {
+
+ private Parcel mParcel;
+
+ @Before
+ public void setUp() throws Exception {
+ mParcel = Parcel.obtain();
+ }
+
+ @Test
+ public void testConfigurationChange() {
+ // Write to parcel
+ ConfigurationChangeItem item = ConfigurationChangeItem.obtain(config());
+ writeAndPrepareForReading(item);
+
+ // Read from parcel and assert
+ ConfigurationChangeItem result = ConfigurationChangeItem.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(item.hashCode(), result.hashCode());
+ assertTrue(item.equals(result));
+ }
+
+ @Test
+ public void testActivityConfigChange() {
+ // Write to parcel
+ ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain(config());
+ writeAndPrepareForReading(item);
+
+ // Read from parcel and assert
+ ActivityConfigurationChangeItem result =
+ ActivityConfigurationChangeItem.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(item.hashCode(), result.hashCode());
+ assertTrue(item.equals(result));
+ }
+
+ @Test
+ public void testMoveToDisplay() {
+ // Write to parcel
+ MoveToDisplayItem item = MoveToDisplayItem.obtain(4 /* targetDisplayId */, config());
+ writeAndPrepareForReading(item);
+
+ // Read from parcel and assert
+ MoveToDisplayItem result = MoveToDisplayItem.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(item.hashCode(), result.hashCode());
+ assertTrue(item.equals(result));
+ }
+
+ @Test
+ public void testNewIntent() {
+ // Write to parcel
+ NewIntentItem item = NewIntentItem.obtain(referrerIntentList(), true /* pause */);
+ writeAndPrepareForReading(item);
+
+ // Read from parcel and assert
+ NewIntentItem result = NewIntentItem.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(item.hashCode(), result.hashCode());
+ assertTrue(item.equals(result));
+ }
+
+ @Test
+ public void testActivityResult() {
+ // Write to parcel
+ ActivityResultItem item = ActivityResultItem.obtain(resultInfoList());
+ writeAndPrepareForReading(item);
+
+ // Read from parcel and assert
+ ActivityResultItem result = ActivityResultItem.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(item.hashCode(), result.hashCode());
+ assertTrue(item.equals(result));
+ }
+
+ @Test
+ public void testPipModeChange() {
+ // Write to parcel
+ PipModeChangeItem item = PipModeChangeItem.obtain(true /* isInPipMode */, config());
+ writeAndPrepareForReading(item);
+
+ // Read from parcel and assert
+ PipModeChangeItem result = PipModeChangeItem.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(item.hashCode(), result.hashCode());
+ assertTrue(item.equals(result));
+ }
+
+ @Test
+ public void testMultiWindowModeChange() {
+ // Write to parcel
+ MultiWindowModeChangeItem item = MultiWindowModeChangeItem.obtain(
+ true /* isInMultiWindowMode */, config());
+ writeAndPrepareForReading(item);
+
+ // Read from parcel and assert
+ MultiWindowModeChangeItem result =
+ MultiWindowModeChangeItem.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(item.hashCode(), result.hashCode());
+ assertTrue(item.equals(result));
+ }
+
+ @Test
+ public void testWindowVisibilityChange() {
+ // Write to parcel
+ WindowVisibilityItem item = WindowVisibilityItem.obtain(true /* showWindow */);
+ writeAndPrepareForReading(item);
+
+ // Read from parcel and assert
+ WindowVisibilityItem result = WindowVisibilityItem.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(item.hashCode(), result.hashCode());
+ assertTrue(item.equals(result));
+
+ // Check different value
+ item = WindowVisibilityItem.obtain(false);
+
+ mParcel = Parcel.obtain();
+ writeAndPrepareForReading(item);
+
+ // Read from parcel and assert
+ result = WindowVisibilityItem.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(item.hashCode(), result.hashCode());
+ assertTrue(item.equals(result));
+ }
+
+ @Test
+ public void testDestroy() {
+ DestroyActivityItem item = DestroyActivityItem.obtain(true /* finished */,
+ 135 /* configChanges */);
+ writeAndPrepareForReading(item);
+
+ // Read from parcel and assert
+ DestroyActivityItem result = DestroyActivityItem.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(item.hashCode(), result.hashCode());
+ assertTrue(item.equals(result));
+ }
+
+ @Test
+ public void testLaunch() {
+ // Write to parcel
+ Intent intent = new Intent("action");
+ int ident = 57;
+ ActivityInfo activityInfo = new ActivityInfo();
+ activityInfo.flags = 42;
+ activityInfo.maxAspectRatio = 2.4f;
+ activityInfo.launchToken = "token";
+ activityInfo.applicationInfo = new ApplicationInfo();
+ activityInfo.packageName = "packageName";
+ activityInfo.name = "name";
+ Configuration overrideConfig = new Configuration();
+ overrideConfig.assetsSeq = 5;
+ CompatibilityInfo compat = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
+ String referrer = "referrer";
+ int procState = 4;
+ Bundle bundle = new Bundle();
+ bundle.putString("key", "value");
+ PersistableBundle persistableBundle = new PersistableBundle();
+ persistableBundle.putInt("k", 4);
+
+ LaunchActivityItem item = LaunchActivityItem.obtain(intent, ident, activityInfo,
+ config(), overrideConfig, compat, referrer, null /* voiceInteractor */,
+ procState, bundle, persistableBundle, resultInfoList(), referrerIntentList(),
+ true /* isForward */, null /* profilerInfo */);
+ writeAndPrepareForReading(item);
+
+ // Read from parcel and assert
+ LaunchActivityItem result = LaunchActivityItem.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(item.hashCode(), result.hashCode());
+ assertTrue(item.equals(result));
+ }
+
+ @Test
+ public void testPause() {
+ // Write to parcel
+ PauseActivityItem item = PauseActivityItem.obtain(true /* finished */,
+ true /* userLeaving */, 135 /* configChanges */, true /* dontReport */);
+ writeAndPrepareForReading(item);
+
+ // Read from parcel and assert
+ PauseActivityItem result = PauseActivityItem.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(item.hashCode(), result.hashCode());
+ assertTrue(item.equals(result));
+ }
+
+ @Test
+ public void testResume() {
+ // Write to parcel
+ ResumeActivityItem item = ResumeActivityItem.obtain(27 /* procState */,
+ true /* isForward */);
+ writeAndPrepareForReading(item);
+
+ // Read from parcel and assert
+ ResumeActivityItem result = ResumeActivityItem.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(item.hashCode(), result.hashCode());
+ assertTrue(item.equals(result));
+ }
+
+ @Test
+ public void testStop() {
+ // Write to parcel
+ StopActivityItem item = StopActivityItem.obtain(true /* showWindow */,
+ 14 /* configChanges */);
+ writeAndPrepareForReading(item);
+
+ // Read from parcel and assert
+ StopActivityItem result = StopActivityItem.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(item.hashCode(), result.hashCode());
+ assertTrue(item.equals(result));
+ }
+
+ @Test
+ public void testClientTransaction() {
+ // Write to parcel
+ WindowVisibilityItem callback1 = WindowVisibilityItem.obtain(true);
+ ActivityConfigurationChangeItem callback2 = ActivityConfigurationChangeItem.obtain(
+ config());
+
+ StopActivityItem lifecycleRequest = StopActivityItem.obtain(true /* showWindow */,
+ 78 /* configChanges */);
+
+ IApplicationThread appThread = new StubAppThread();
+ Binder activityToken = new Binder();
+
+ ClientTransaction transaction = ClientTransaction.obtain(appThread, activityToken);
+ transaction.addCallback(callback1);
+ transaction.addCallback(callback2);
+ transaction.setLifecycleStateRequest(lifecycleRequest);
+
+ writeAndPrepareForReading(transaction);
+
+ // Read from parcel and assert
+ ClientTransaction result = ClientTransaction.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(transaction.hashCode(), result.hashCode());
+ assertTrue(transaction.equals(result));
+ }
+
+ @Test
+ public void testClientTransactionCallbacksOnly() {
+ // Write to parcel
+ WindowVisibilityItem callback1 = WindowVisibilityItem.obtain(true);
+ ActivityConfigurationChangeItem callback2 = ActivityConfigurationChangeItem.obtain(
+ config());
+
+ IApplicationThread appThread = new StubAppThread();
+ Binder activityToken = new Binder();
+
+ ClientTransaction transaction = ClientTransaction.obtain(appThread, activityToken);
+ transaction.addCallback(callback1);
+ transaction.addCallback(callback2);
+
+ writeAndPrepareForReading(transaction);
+
+ // Read from parcel and assert
+ ClientTransaction result = ClientTransaction.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(transaction.hashCode(), result.hashCode());
+ assertTrue(transaction.equals(result));
+ }
+
+ @Test
+ public void testClientTransactionLifecycleOnly() {
+ // Write to parcel
+ StopActivityItem lifecycleRequest = StopActivityItem.obtain(true /* showWindow */,
+ 78 /* configChanges */);
+
+ IApplicationThread appThread = new StubAppThread();
+ Binder activityToken = new Binder();
+
+ ClientTransaction transaction = ClientTransaction.obtain(appThread, activityToken);
+ transaction.setLifecycleStateRequest(lifecycleRequest);
+
+ writeAndPrepareForReading(transaction);
+
+ // Read from parcel and assert
+ ClientTransaction result = ClientTransaction.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(transaction.hashCode(), result.hashCode());
+ assertTrue(transaction.equals(result));
+ }
+
+ /** Write to {@link #mParcel} and reset its position to prepare for reading from the start. */
+ private void writeAndPrepareForReading(Parcelable parcelable) {
+ parcelable.writeToParcel(mParcel, 0 /* flags */);
+ mParcel.setDataPosition(0);
+ }
+
+ /** Stub implementation of IApplicationThread that can be presented as {@link Binder}. */
+ class StubAppThread extends android.app.IApplicationThread.Stub {
+
+ @Override
+ public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
+ }
+
+ @Override
+ public void scheduleReceiver(Intent intent, ActivityInfo activityInfo,
+ CompatibilityInfo compatibilityInfo, int i, String s, Bundle bundle, boolean b,
+ int i1, int i2) throws RemoteException {
+ }
+
+ @Override
+ public void scheduleCreateService(IBinder iBinder, ServiceInfo serviceInfo,
+ CompatibilityInfo compatibilityInfo, int i) throws RemoteException {
+ }
+
+ @Override
+ public void scheduleStopService(IBinder iBinder) throws RemoteException {
+ }
+
+ @Override
+ public void bindApplication(String s, ApplicationInfo applicationInfo,
+ List<ProviderInfo> list, ComponentName componentName, ProfilerInfo profilerInfo,
+ Bundle bundle, IInstrumentationWatcher iInstrumentationWatcher,
+ IUiAutomationConnection iUiAutomationConnection, int i, boolean b, boolean b1,
+ boolean b2, boolean b3, Configuration configuration,
+ CompatibilityInfo compatibilityInfo, Map map, Bundle bundle1, String s1)
+ throws RemoteException {
+ }
+
+ @Override
+ public void scheduleExit() throws RemoteException {
+ }
+
+ @Override
+ public void scheduleServiceArgs(IBinder iBinder, ParceledListSlice parceledListSlice)
+ throws RemoteException {
+ }
+
+ @Override
+ public void updateTimeZone() throws RemoteException {
+ }
+
+ @Override
+ public void processInBackground() throws RemoteException {
+ }
+
+ @Override
+ public void scheduleBindService(IBinder iBinder, Intent intent, boolean b, int i)
+ throws RemoteException {
+ }
+
+ @Override
+ public void scheduleUnbindService(IBinder iBinder, Intent intent) throws RemoteException {
+ }
+
+ @Override
+ public void dumpService(ParcelFileDescriptor parcelFileDescriptor, IBinder iBinder,
+ String[] strings) throws RemoteException {
+ }
+
+ @Override
+ public void scheduleRegisteredReceiver(IIntentReceiver iIntentReceiver, Intent intent,
+ int i, String s, Bundle bundle, boolean b, boolean b1, int i1, int i2)
+ throws RemoteException {
+ }
+
+ @Override
+ public void scheduleLowMemory() throws RemoteException {
+ }
+
+ @Override
+ public void scheduleRelaunchActivity(IBinder iBinder, List<ResultInfo> list,
+ List<ReferrerIntent> list1, int i, boolean b, Configuration configuration,
+ Configuration configuration1, boolean b1) throws RemoteException {
+ }
+
+ @Override
+ public void scheduleSleeping(IBinder iBinder, boolean b) throws RemoteException {
+ }
+
+ @Override
+ public void profilerControl(boolean b, ProfilerInfo profilerInfo, int i)
+ throws RemoteException {
+ }
+
+ @Override
+ public void setSchedulingGroup(int i) throws RemoteException {
+ }
+
+ @Override
+ public void scheduleCreateBackupAgent(ApplicationInfo applicationInfo,
+ CompatibilityInfo compatibilityInfo, int i) throws RemoteException {
+ }
+
+ @Override
+ public void scheduleDestroyBackupAgent(ApplicationInfo applicationInfo,
+ CompatibilityInfo compatibilityInfo) throws RemoteException {
+ }
+
+ @Override
+ public void scheduleOnNewActivityOptions(IBinder iBinder, Bundle bundle)
+ throws RemoteException {
+ }
+
+ @Override
+ public void scheduleSuicide() throws RemoteException {
+ }
+
+ @Override
+ public void dispatchPackageBroadcast(int i, String[] strings) throws RemoteException {
+ }
+
+ @Override
+ public void scheduleCrash(String s) throws RemoteException {
+ }
+
+ @Override
+ public void dumpActivity(ParcelFileDescriptor parcelFileDescriptor, IBinder iBinder,
+ String s, String[] strings) throws RemoteException {
+ }
+
+ @Override
+ public void clearDnsCache() throws RemoteException {
+ }
+
+ @Override
+ public void setHttpProxy(String s, String s1, String s2, Uri uri) throws RemoteException {
+ }
+
+ @Override
+ public void setCoreSettings(Bundle bundle) throws RemoteException {
+ }
+
+ @Override
+ public void updatePackageCompatibilityInfo(String s, CompatibilityInfo compatibilityInfo)
+ throws RemoteException {
+ }
+
+ @Override
+ public void scheduleTrimMemory(int i) throws RemoteException {
+ }
+
+ @Override
+ public void dumpMemInfo(ParcelFileDescriptor parcelFileDescriptor,
+ Debug.MemoryInfo memoryInfo, boolean b, boolean b1, boolean b2, boolean b3,
+ boolean b4, String[] strings) throws RemoteException {
+ }
+
+ @Override
+ public void dumpGfxInfo(ParcelFileDescriptor parcelFileDescriptor, String[] strings)
+ throws RemoteException {
+ }
+
+ @Override
+ public void dumpProvider(ParcelFileDescriptor parcelFileDescriptor, IBinder iBinder,
+ String[] strings) throws RemoteException {
+ }
+
+ @Override
+ public void dumpDbInfo(ParcelFileDescriptor parcelFileDescriptor, String[] strings)
+ throws RemoteException {
+ }
+
+ @Override
+ public void unstableProviderDied(IBinder iBinder) throws RemoteException {
+ }
+
+ @Override
+ public void requestAssistContextExtras(IBinder iBinder, IBinder iBinder1, int i, int i1,
+ int i2) throws RemoteException {
+ }
+
+ @Override
+ public void scheduleTranslucentConversionComplete(IBinder iBinder, boolean b)
+ throws RemoteException {
+ }
+
+ @Override
+ public void setProcessState(int i) throws RemoteException {
+ }
+
+ @Override
+ public void scheduleInstallProvider(ProviderInfo providerInfo) throws RemoteException {
+ }
+
+ @Override
+ public void updateTimePrefs(int i) throws RemoteException {
+ }
+
+ @Override
+ public void scheduleEnterAnimationComplete(IBinder iBinder) throws RemoteException {
+ }
+
+ @Override
+ public void notifyCleartextNetwork(byte[] bytes) throws RemoteException {
+ }
+
+ @Override
+ public void startBinderTracking() throws RemoteException {
+ }
+
+ @Override
+ public void stopBinderTrackingAndDump(ParcelFileDescriptor parcelFileDescriptor)
+ throws RemoteException {
+ }
+
+ @Override
+ public void scheduleLocalVoiceInteractionStarted(IBinder iBinder,
+ IVoiceInteractor iVoiceInteractor) throws RemoteException {
+ }
+
+ @Override
+ public void handleTrustStorageUpdate() throws RemoteException {
+ }
+
+ @Override
+ public void attachAgent(String s) throws RemoteException {
+ }
+
+ @Override
+ public void scheduleApplicationInfoChanged(ApplicationInfo applicationInfo)
+ throws RemoteException {
+ }
+
+ @Override
+ public void setNetworkBlockSeq(long l) throws RemoteException {
+ }
+
+ @Override
+ public void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, String path,
+ ParcelFileDescriptor fd) {
+ }
+
+ @Override
+ public final void runIsolatedEntryPoint(String entryPoint, String[] entryPointArgs) {
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
index 5f6f62a..978ea7a 100644
--- a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
@@ -45,8 +45,9 @@
@LargeTest
@RunWith(AndroidJUnit4.class)
abstract class AbstractCrossUserContentResolverTest {
- private final static int TIMEOUT_SERVICE_CONNECTION_SEC = 4;
- private final static int TIMEOUT_CONTENT_CHANGE_SEC = 4;
+ private static final int TIMEOUT_SERVICE_CONNECTION_SEC = 4;
+ private static final int TIMEOUT_CONTENT_CHANGE_SEC = 4;
+ private static final int TIMEOUT_USER_UNLOCK_SEC = 4;
private Context mContext;
protected UserManager mUm;
@@ -61,7 +62,7 @@
mCrossUserId = userInfo.id;
final PackageManager pm = mContext.getPackageManager();
pm.installExistingPackageAsUser(mContext.getPackageName(), mCrossUserId);
- ActivityManager.getService().startUserInBackground(mCrossUserId);
+ unlockUser();
final CountDownLatch connectionLatch = new CountDownLatch(1);
mServiceConnection = new CrossUserContentServiceConnection(connectionLatch);
@@ -77,6 +78,30 @@
protected abstract UserInfo createUser() throws RemoteException ;
+ private void unlockUser() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL)
+ == mCrossUserId) {
+ latch.countDown();
+ }
+ }
+ };
+ mContext.registerReceiverAsUser(receiver, UserHandle.of(mCrossUserId),
+ new IntentFilter(Intent.ACTION_USER_UNLOCKED), null, null);
+ ActivityManager.getService().startUserInBackground(mCrossUserId);
+
+ try {
+ if (!latch.await(TIMEOUT_USER_UNLOCK_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for the u" + mCrossUserId + " to unlock");
+ }
+ } finally {
+ mContext.unregisterReceiver(receiver);
+ }
+ }
+
@After
public void tearDown() throws Exception {
if (mCrossUserId != -1) {
diff --git a/core/tests/coretests/src/android/content/pm/crossprofile/CrossProfileAppsTest.java b/core/tests/coretests/src/android/content/pm/crossprofile/CrossProfileAppsTest.java
new file mode 100644
index 0000000..80e4c02
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/crossprofile/CrossProfileAppsTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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 android.content.pm.crossprofile;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.platform.test.annotations.Presubmit;
+
+import com.android.internal.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Build/Install/Run:
+ * bit FrameworksCoreTests:android.content.pm.crossprofile.CrossProfileAppsTest
+ */
+@Presubmit
+@RunWith(MockitoJUnitRunner.class)
+public class CrossProfileAppsTest {
+ private static final UserHandle PERSONAL_PROFILE = UserHandle.of(0);
+ private static final UserHandle MANAGED_PROFILE = UserHandle.of(10);
+ private static final String MY_PACKAGE = "my.package";
+
+ private List<UserHandle> mTargetProfiles;
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private ICrossProfileApps mService;
+ @Mock
+ private Resources mResources;
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private Drawable mDrawable;
+ private CrossProfileApps mCrossProfileApps;
+
+ @Before
+ public void initCrossProfileApps() {
+ mCrossProfileApps = new CrossProfileApps(mContext, mService);
+ }
+
+ @Before
+ public void mockContext() {
+ when(mContext.getPackageName()).thenReturn(MY_PACKAGE);
+ when(mContext.getSystemServiceName(UserManager.class)).thenReturn(Context.USER_SERVICE);
+ when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+ }
+
+ @Before
+ public void mockResources() {
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getDrawable(anyInt(), nullable(Resources.Theme.class)))
+ .thenReturn(mDrawable);
+ }
+
+ @Before
+ public void initUsers() throws Exception {
+ when(mUserManager.isManagedProfile(PERSONAL_PROFILE.getIdentifier())).thenReturn(false);
+ when(mUserManager.isManagedProfile(MANAGED_PROFILE.getIdentifier())).thenReturn(true);
+
+ mTargetProfiles = new ArrayList<>();
+ when(mService.getTargetUserProfiles(MY_PACKAGE)).thenReturn(mTargetProfiles);
+ }
+
+ @Test
+ public void getProfileSwitchingLabel_managedProfile() {
+ setValidTargetProfile(MANAGED_PROFILE);
+
+ mCrossProfileApps.getProfileSwitchingLabel(MANAGED_PROFILE);
+ verify(mResources).getString(R.string.managed_profile_label);
+ }
+
+ @Test
+ public void getProfileSwitchingLabel_personalProfile() {
+ setValidTargetProfile(PERSONAL_PROFILE);
+
+ mCrossProfileApps.getProfileSwitchingLabel(PERSONAL_PROFILE);
+ verify(mResources).getString(R.string.user_owner_label);
+ }
+
+ @Test(expected = SecurityException.class)
+ public void getProfileSwitchingLabel_securityException() {
+ mCrossProfileApps.getProfileSwitchingLabel(PERSONAL_PROFILE);
+ }
+
+ @Test
+ public void getProfileSwitchingIcon_managedProfile() {
+ setValidTargetProfile(MANAGED_PROFILE);
+
+ mCrossProfileApps.getProfileSwitchingIcon(MANAGED_PROFILE);
+ verify(mResources).getDrawable(R.drawable.ic_corp_badge, null);
+ }
+
+ @Test
+ public void getProfileSwitchingIcon_personalProfile() {
+ setValidTargetProfile(PERSONAL_PROFILE);
+
+ mCrossProfileApps.getProfileSwitchingIcon(PERSONAL_PROFILE);
+ verify(mResources).getDrawable(R.drawable.ic_account_circle, null);
+ }
+
+ @Test(expected = SecurityException.class)
+ public void getProfileSwitchingIcon_securityException() {
+ mCrossProfileApps.getProfileSwitchingIcon(PERSONAL_PROFILE);
+ }
+
+ private void setValidTargetProfile(UserHandle userHandle) {
+ mTargetProfiles.add(userHandle);
+ }
+}
diff --git a/core/tests/coretests/src/android/os/EnvironmentTest.java b/core/tests/coretests/src/android/os/EnvironmentTest.java
new file mode 100644
index 0000000..5189df5
--- /dev/null
+++ b/core/tests/coretests/src/android/os/EnvironmentTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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 android.os;
+
+import static android.os.Environment.HAS_ANDROID;
+import static android.os.Environment.HAS_DCIM;
+import static android.os.Environment.HAS_DOWNLOADS;
+import static android.os.Environment.HAS_OTHER;
+import static android.os.Environment.classifyExternalStorageDirectory;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+
+@RunWith(AndroidJUnit4.class)
+public class EnvironmentTest {
+ private File dir;
+
+ private Context getContext() {
+ return InstrumentationRegistry.getContext();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ dir = getContext().getDir("testing", Context.MODE_PRIVATE);
+ FileUtils.deleteContents(dir);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ FileUtils.deleteContents(dir);
+ }
+
+ @Test
+ public void testClassify_empty() {
+ assertEquals(0, classifyExternalStorageDirectory(dir));
+ }
+
+ @Test
+ public void testClassify_emptyDirs() {
+ Environment.buildPath(dir, "DCIM").mkdirs();
+ Environment.buildPath(dir, "DCIM", "January").mkdirs();
+ Environment.buildPath(dir, "Downloads").mkdirs();
+ Environment.buildPath(dir, "LOST.DIR").mkdirs();
+ assertEquals(0, classifyExternalStorageDirectory(dir));
+ }
+
+ @Test
+ public void testClassify_emptyFactory() throws Exception {
+ Environment.buildPath(dir, "autorun.inf").createNewFile();
+ Environment.buildPath(dir, "LaunchU3.exe").createNewFile();
+ Environment.buildPath(dir, "LaunchPad.zip").createNewFile();
+ assertEquals(0, classifyExternalStorageDirectory(dir));
+ }
+
+ @Test
+ public void testClassify_photos() throws Exception {
+ Environment.buildPath(dir, "DCIM").mkdirs();
+ Environment.buildPath(dir, "DCIM", "IMG_1024.JPG").createNewFile();
+ Environment.buildPath(dir, "Download").mkdirs();
+ Environment.buildPath(dir, "Download", "foobar.pdf").createNewFile();
+ assertEquals(HAS_DCIM | HAS_DOWNLOADS, classifyExternalStorageDirectory(dir));
+ }
+
+ @Test
+ public void testClassify_other() throws Exception {
+ Environment.buildPath(dir, "Android").mkdirs();
+ Environment.buildPath(dir, "Android", "com.example").mkdirs();
+ Environment.buildPath(dir, "Android", "com.example", "internal.dat").createNewFile();
+ Environment.buildPath(dir, "Linux").mkdirs();
+ Environment.buildPath(dir, "Linux", "install-amd64-minimal-20170907.iso").createNewFile();
+ assertEquals(HAS_ANDROID | HAS_OTHER, classifyExternalStorageDirectory(dir));
+ }
+
+ @Test
+ public void testClassify_otherRoot() throws Exception {
+ Environment.buildPath(dir, "Taxes.pdf").createNewFile();
+ assertEquals(HAS_OTHER, classifyExternalStorageDirectory(dir));
+ }
+}
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 3a751af..cd20192 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -21,15 +21,24 @@
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
import android.content.Context;
import android.provider.DocumentsContract.Document;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
import libcore.io.IoUtils;
import com.google.android.collect.Sets;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
@@ -37,8 +46,8 @@
import java.util.Arrays;
import java.util.HashSet;
-@MediumTest
-public class FileUtilsTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class FileUtilsTest {
private static final String TEST_DATA =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
@@ -47,10 +56,12 @@
private File mCopyFile;
private File mTarget;
+ private Context getContext() {
+ return InstrumentationRegistry.getContext();
+ }
- @Override
- protected void setUp() throws Exception {
- super.setUp();
+ @Before
+ public void setUp() throws Exception {
mDir = getContext().getDir("testing", Context.MODE_PRIVATE);
mTestFile = new File(mDir, "test.file");
mCopyFile = new File(mDir, "copy.file");
@@ -59,14 +70,15 @@
FileUtils.deleteContents(mTarget);
}
- @Override
- protected void tearDown() throws Exception {
+ @After
+ public void tearDown() throws Exception {
IoUtils.deleteContents(mDir);
FileUtils.deleteContents(mTarget);
}
// TODO: test setPermissions(), getPermissions()
+ @Test
public void testCopyFile() throws Exception {
stageFile(mTestFile, TEST_DATA);
assertFalse(mCopyFile.exists());
@@ -75,6 +87,7 @@
assertEquals(TEST_DATA, FileUtils.readTextFile(mCopyFile, 0, null));
}
+ @Test
public void testCopyToFile() throws Exception {
final String s = "Foo Bar";
assertFalse(mCopyFile.exists());
@@ -83,6 +96,7 @@
assertEquals(s, FileUtils.readTextFile(mCopyFile, 0, null));
}
+ @Test
public void testIsFilenameSafe() throws Exception {
assertTrue(FileUtils.isFilenameSafe(new File("foobar")));
assertTrue(FileUtils.isFilenameSafe(new File("a_b-c=d.e/0,1+23")));
@@ -90,6 +104,7 @@
assertFalse(FileUtils.isFilenameSafe(new File("foo\nbar")));
}
+ @Test
public void testReadTextFile() throws Exception {
stageFile(mTestFile, TEST_DATA);
@@ -110,6 +125,7 @@
assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, -100, "<>"));
}
+ @Test
public void testReadTextFileWithZeroLengthFile() throws Exception {
stageFile(mTestFile, TEST_DATA);
new FileOutputStream(mTestFile).close(); // Zero out the file
@@ -120,6 +136,7 @@
assertEquals("", FileUtils.readTextFile(mTestFile, -10, "<>"));
}
+ @Test
public void testContains() throws Exception {
assertTrue(FileUtils.contains(new File("/"), new File("/moo.txt")));
assertTrue(FileUtils.contains(new File("/"), new File("/")));
@@ -137,11 +154,13 @@
assertFalse(FileUtils.contains(new File("/sdcard/"), new File("/sdcard.txt")));
}
+ @Test
public void testDeleteOlderEmptyDir() throws Exception {
FileUtils.deleteOlderFiles(mDir, 10, WEEK_IN_MILLIS);
assertDirContents();
}
+ @Test
public void testDeleteOlderTypical() throws Exception {
touch("file1", HOUR_IN_MILLIS);
touch("file2", 1 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
@@ -152,6 +171,7 @@
assertDirContents("file1", "file2", "file3");
}
+ @Test
public void testDeleteOlderInFuture() throws Exception {
touch("file1", -HOUR_IN_MILLIS);
touch("file2", HOUR_IN_MILLIS);
@@ -166,6 +186,7 @@
assertDirContents("file1", "file2");
}
+ @Test
public void testDeleteOlderOnlyAge() throws Exception {
touch("file1", HOUR_IN_MILLIS);
touch("file2", 1 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
@@ -177,6 +198,7 @@
assertDirContents("file1");
}
+ @Test
public void testDeleteOlderOnlyCount() throws Exception {
touch("file1", HOUR_IN_MILLIS);
touch("file2", 1 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
@@ -188,6 +210,7 @@
assertDirContents("file1", "file2");
}
+ @Test
public void testValidExtFilename() throws Exception {
assertTrue(FileUtils.isValidExtFilename("a"));
assertTrue(FileUtils.isValidExtFilename("foo.bar"));
@@ -208,6 +231,7 @@
assertEquals("foo.bar", FileUtils.buildValidExtFilename("foo.bar"));
}
+ @Test
public void testValidFatFilename() throws Exception {
assertTrue(FileUtils.isValidFatFilename("a"));
assertTrue(FileUtils.isValidFatFilename("foo bar.baz"));
@@ -233,6 +257,7 @@
assertEquals("foo_bar__baz", FileUtils.buildValidFatFilename("foo?bar**baz"));
}
+ @Test
public void testTrimFilename() throws Exception {
assertEquals("short.txt", FileUtils.trimFilename("short.txt", 16));
assertEquals("extrem...eme.txt", FileUtils.trimFilename("extremelylongfilename.txt", 16));
@@ -245,6 +270,7 @@
assertEquals("a...z", FileUtils.trimFilename(unicode, 6));
}
+ @Test
public void testBuildUniqueFile_normal() throws Exception {
assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test"));
assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.jpg"));
@@ -263,6 +289,7 @@
FileUtils.buildUniqueFile(mTarget, "application/x-flac", "test.flac"));
}
+ @Test
public void testBuildUniqueFile_unknown() throws Exception {
assertNameEquals("test",
FileUtils.buildUniqueFile(mTarget, "application/octet-stream", "test"));
@@ -275,6 +302,7 @@
assertNameEquals("test.lolz", FileUtils.buildUniqueFile(mTarget, "lolz/lolz", "test.lolz"));
}
+ @Test
public void testBuildUniqueFile_dir() throws Exception {
assertNameEquals("test", FileUtils.buildUniqueFile(mTarget, Document.MIME_TYPE_DIR, "test"));
new File(mTarget, "test").mkdir();
@@ -288,6 +316,7 @@
FileUtils.buildUniqueFile(mTarget, Document.MIME_TYPE_DIR, "test.jpg"));
}
+ @Test
public void testBuildUniqueFile_increment() throws Exception {
assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.jpg"));
new File(mTarget, "test.jpg").createNewFile();
@@ -298,6 +327,7 @@
FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.jpg"));
}
+ @Test
public void testBuildUniqueFile_mimeless() throws Exception {
assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "test.jpg"));
new File(mTarget, "test.jpg").createNewFile();
@@ -312,6 +342,7 @@
assertNameEquals("test.foo (1).bar", FileUtils.buildUniqueFile(mTarget, "test.foo.bar"));
}
+ @Test
public void testRoundStorageSize() throws Exception {
final long M128 = 128000000L;
final long M256 = 256000000L;
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 492ef72..0982a4b 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -108,7 +108,6 @@
Settings.Global.APP_IDLE_CONSTANTS,
Settings.Global.ASSISTED_GPS_ENABLED,
Settings.Global.AUDIO_SAFE_VOLUME_STATE,
- Settings.Global.BACKUP_REFACTORED_SERVICE_DISABLED,
Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD,
Settings.Global.BATTERY_DISCHARGE_THRESHOLD,
Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS,
@@ -127,6 +126,7 @@
Settings.Global.BLUETOOTH_PAN_PRIORITY_PREFIX,
Settings.Global.BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX,
Settings.Global.BLUETOOTH_SAP_PRIORITY_PREFIX,
+ Settings.Global.BLUETOOTH_HEARING_AID_PRIORITY_PREFIX,
Settings.Global.BOOT_COUNT,
Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL,
Settings.Global.CAPTIVE_PORTAL_HTTPS_URL,
@@ -194,6 +194,7 @@
Settings.Global.DROPBOX_RESERVE_PERCENT,
Settings.Global.DROPBOX_TAG_PREFIX,
Settings.Global.EMERGENCY_AFFORDANCE_NEEDED,
+ Settings.Global.EMULATE_DISPLAY_CUTOUT,
Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED,
Settings.Global.ENABLE_CACHE_QUOTA_CALCULATION,
Settings.Global.ENABLE_CELLULAR_ON_BOOT,
@@ -230,6 +231,7 @@
Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
+ Settings.Global.LOCATION_GLOBAL_KILL_SWITCH,
Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED,
Settings.Global.LOCK_SOUND,
Settings.Global.LOW_BATTERY_SOUND,
@@ -417,7 +419,13 @@
private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
newHashSet(
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
- Settings.Secure.AUTOFILL_FEATURE_FIELD_DETECTION,
+ // TODO(b/67867469): Move autofill settings below to
+ // BACKUP_BLACKLISTED_SYSTEM_SETTINGS once feature is moved out of experimental
+ Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION,
+ Settings.Secure.AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE,
+ Settings.Secure.AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE,
+ Settings.Secure.AUTOFILL_USER_DATA_MAX_VALUE_LENGTH,
+ Settings.Secure.AUTOFILL_USER_DATA_MIN_VALUE_LENGTH,
Settings.Secure.ALLOWED_GEOLOCATION_ORIGINS,
Settings.Secure.ALWAYS_ON_VPN_APP,
Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
diff --git a/core/tests/coretests/src/android/text/MeasuredTextTest.java b/core/tests/coretests/src/android/text/MeasuredTextTest.java
new file mode 100644
index 0000000..ddef0c6
--- /dev/null
+++ b/core/tests/coretests/src/android/text/MeasuredTextTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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 android.text;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MeasuredTextTest {
+ private static final TextDirectionHeuristic LTR = TextDirectionHeuristics.LTR;
+ private static final TextDirectionHeuristic RTL = TextDirectionHeuristics.RTL;
+
+ private static final TextPaint PAINT = new TextPaint();
+ static {
+ // The test font has following coverage and width.
+ // U+0020: 10em
+ // U+002E (.): 10em
+ // U+0043 (C): 100em
+ // U+0049 (I): 1em
+ // U+004C (L): 50em
+ // U+0056 (V): 5em
+ // U+0058 (X): 10em
+ // U+005F (_): 0em
+ // U+FFFD (invalid surrogate will be replaced to this): 7em
+ // U+10331 (\uD800\uDF31): 10em
+ Context context = InstrumentationRegistry.getTargetContext();
+ PAINT.setTypeface(Typeface.createFromAsset(context.getAssets(),
+ "fonts/StaticLayoutLineBreakingTestFont.ttf"));
+ PAINT.setTextSize(1.0f); // Make 1em == 1px.
+ }
+
+ private String charsToString(char[] chars) {
+ return (new StringBuilder()).append(chars).toString();
+ }
+
+ @Test
+ public void buildForBidi() {
+ MeasuredText mt = null;
+
+ mt = MeasuredText.buildForBidi("XXX", 0, 3, LTR, null);
+ assertNotNull(mt);
+ assertNotNull(mt.getChars());
+ assertEquals("XXX", charsToString(mt.getChars()));
+ assertEquals(Layout.DIR_LEFT_TO_RIGHT, mt.getParagraphDir());
+ assertNotNull(mt.getDirections(0, 3));
+ assertEquals(0, mt.getWholeWidth(), 0);
+ assertEquals(0, mt.getWidths().size());
+ assertEquals(0, mt.getSpanEndCache().size());
+ assertEquals(0, mt.getFontMetrics().size());
+ assertEquals(0, mt.getNativePtr());
+
+ // Recycle it
+ MeasuredText mt2 = MeasuredText.buildForBidi("_VVV_", 1, 4, RTL, mt);
+ assertEquals(mt2, mt);
+ assertNotNull(mt2.getChars());
+ assertEquals("VVV", charsToString(mt.getChars()));
+ assertNotNull(mt2.getDirections(0, 3));
+ assertEquals(0, mt2.getWholeWidth(), 0);
+ assertEquals(0, mt2.getWidths().size());
+ assertEquals(0, mt2.getSpanEndCache().size());
+ assertEquals(0, mt2.getFontMetrics().size());
+ assertEquals(0, mt2.getNativePtr());
+
+ mt2.recycle();
+ }
+
+ @Test
+ public void buildForMeasurement() {
+ MeasuredText mt = null;
+
+ mt = MeasuredText.buildForMeasurement(PAINT, "XXX", 0, 3, LTR, null);
+ assertNotNull(mt);
+ assertNotNull(mt.getChars());
+ assertEquals("XXX", charsToString(mt.getChars()));
+ assertEquals(Layout.DIR_LEFT_TO_RIGHT, mt.getParagraphDir());
+ assertNotNull(mt.getDirections(0, 3));
+ assertEquals(30, mt.getWholeWidth(), 0);
+ assertEquals(3, mt.getWidths().size());
+ assertEquals(10, mt.getWidths().get(0), 0);
+ assertEquals(10, mt.getWidths().get(1), 0);
+ assertEquals(10, mt.getWidths().get(2), 0);
+ assertEquals(0, mt.getSpanEndCache().size());
+ assertEquals(0, mt.getFontMetrics().size());
+ assertEquals(0, mt.getNativePtr());
+
+ // Recycle it
+ MeasuredText mt2 = MeasuredText.buildForMeasurement(PAINT, "_VVV_", 1, 4, RTL, mt);
+ assertEquals(mt2, mt);
+ assertNotNull(mt2.getChars());
+ assertEquals("VVV", charsToString(mt.getChars()));
+ assertEquals(Layout.DIR_RIGHT_TO_LEFT, mt2.getParagraphDir());
+ assertNotNull(mt2.getDirections(0, 3));
+ assertEquals(15, mt2.getWholeWidth(), 0);
+ assertEquals(3, mt2.getWidths().size());
+ assertEquals(5, mt2.getWidths().get(0), 0);
+ assertEquals(5, mt2.getWidths().get(1), 0);
+ assertEquals(5, mt2.getWidths().get(2), 0);
+ assertEquals(0, mt2.getSpanEndCache().size());
+ assertEquals(0, mt2.getFontMetrics().size());
+ assertEquals(0, mt2.getNativePtr());
+
+ mt2.recycle();
+ }
+
+ @Test
+ public void buildForStaticLayout() {
+ MeasuredText mt = null;
+
+ mt = MeasuredText.buildForStaticLayout(PAINT, "XXX", 0, 3, LTR, null);
+ assertNotNull(mt);
+ assertNotNull(mt.getChars());
+ assertEquals("XXX", charsToString(mt.getChars()));
+ assertEquals(Layout.DIR_LEFT_TO_RIGHT, mt.getParagraphDir());
+ assertNotNull(mt.getDirections(0, 3));
+ assertEquals(0, mt.getWholeWidth(), 0);
+ assertEquals(0, mt.getWidths().size());
+ assertEquals(1, mt.getSpanEndCache().size());
+ assertEquals(3, mt.getSpanEndCache().get(0));
+ assertNotEquals(0, mt.getFontMetrics().size());
+ assertNotEquals(0, mt.getNativePtr());
+
+ // Recycle it
+ MeasuredText mt2 = MeasuredText.buildForStaticLayout(PAINT, "_VVV_", 1, 4, RTL, mt);
+ assertEquals(mt2, mt);
+ assertNotNull(mt2.getChars());
+ assertEquals("VVV", charsToString(mt.getChars()));
+ assertEquals(Layout.DIR_RIGHT_TO_LEFT, mt2.getParagraphDir());
+ assertNotNull(mt2.getDirections(0, 3));
+ assertEquals(0, mt2.getWholeWidth(), 0);
+ assertEquals(0, mt2.getWidths().size());
+ assertEquals(1, mt2.getSpanEndCache().size());
+ assertEquals(4, mt2.getSpanEndCache().get(0));
+ assertNotEquals(0, mt2.getFontMetrics().size());
+ assertNotEquals(0, mt2.getNativePtr());
+
+ mt2.recycle();
+ }
+
+ @Test
+ public void testFor70146381() {
+ MeasuredText.buildForMeasurement(PAINT, "X…", 0, 2, RTL, null);
+ }
+}
diff --git a/core/tests/coretests/src/android/util/KeyValueListParserTest.java b/core/tests/coretests/src/android/util/KeyValueListParserTest.java
new file mode 100644
index 0000000..038f0b7
--- /dev/null
+++ b/core/tests/coretests/src/android/util/KeyValueListParserTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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 android.util;
+
+import static org.junit.Assert.assertEquals;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link KeyValueListParser}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class KeyValueListParserTest {
+ private static final String TAG = "KeyValueListParserTest";
+ private static final int[] DEFAULT = {1, 2, 3, 4};
+
+ private KeyValueListParser mParser;
+
+ @Before
+ public void setUp() {
+ mParser = new KeyValueListParser(',');
+ }
+
+ @Test
+ public void testParseIntArrayNullInput() throws Exception {
+ mParser.setString(null);
+ int[] result = mParser.getIntArray("test", DEFAULT);
+ assertEquals(DEFAULT, result);
+ }
+
+ @Test
+ public void testParseIntArrayEmptyInput() throws Exception {
+ mParser.setString("test=");
+ int[] result = mParser.getIntArray("test", DEFAULT);
+ assertEquals(DEFAULT, result);
+ }
+
+ @Test
+ public void testParseIntArrayNullKey() throws Exception {
+ mParser.setString("foo=bar,test=100:200,baz=123");
+ int[] result = mParser.getIntArray(null, DEFAULT);
+ assertEquals(DEFAULT, result);
+ }
+
+ @Test
+ public void testParseIntArrayComplexInput() throws Exception {
+ mParser.setString("foo=bar,test=100:200,baz=123");
+ int[] result = mParser.getIntArray("test", DEFAULT);
+ assertEquals(2, result.length);
+ assertEquals(100, result[0]); // respect order
+ assertEquals(200, result[1]);
+ }
+
+ @Test
+ public void testParseIntArrayLeadingSep() throws Exception {
+ mParser.setString("test=:4:5:6");
+ int[] result = mParser.getIntArray("test", DEFAULT);
+ assertEquals(DEFAULT, result);
+ }
+
+ @Test
+ public void testParseIntArrayEmptyItem() throws Exception {
+ mParser.setString("test=:4::6");
+ int[] result = mParser.getIntArray("test", DEFAULT);
+ assertEquals(DEFAULT, result);
+ }
+
+ @Test
+ public void testParseIntArrayTrailingSep() throws Exception {
+ mParser.setString("test=4:5:6:");
+ int[] result = mParser.getIntArray("test", DEFAULT);
+ assertEquals(3, result.length);
+ assertEquals(4, result[0]); // respect order
+ assertEquals(5, result[1]);
+ assertEquals(6, result[2]);
+ }
+
+ @Test
+ public void testParseIntArrayGoodData() throws Exception {
+ mParser.setString("test=4:5:6");
+ int[] result = mParser.getIntArray("test", DEFAULT);
+ assertEquals(3, result.length);
+ assertEquals(4, result[0]); // respect order
+ assertEquals(5, result[1]);
+ assertEquals(6, result[2]);
+ }
+}
diff --git a/core/tests/coretests/src/android/view/DisplayCutoutTest.java b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
new file mode 100644
index 0000000..6dd787d
--- /dev/null
+++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
@@ -0,0 +1,347 @@
+/*
+ * 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 android.view;
+
+import static android.view.DisplayCutout.NO_CUTOUT;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.DisplayCutout.ParcelableWrapper;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class DisplayCutoutTest {
+
+ /** This is not a consistent cutout. Useful for verifying insets in one go though. */
+ final DisplayCutout mCutoutNumbers = new DisplayCutout(
+ new Rect(1, 2, 3, 4),
+ new Rect(5, 6, 7, 8),
+ Arrays.asList(
+ new Point(9, 10),
+ new Point(11, 12),
+ new Point(13, 14),
+ new Point(15, 16)));
+
+ final DisplayCutout mCutoutTop = createCutoutTop();
+
+ @Test
+ public void hasCutout() throws Exception {
+ assertFalse(NO_CUTOUT.hasCutout());
+ assertTrue(mCutoutTop.hasCutout());
+ }
+
+ @Test
+ public void getSafeInsets() throws Exception {
+ assertEquals(1, mCutoutNumbers.getSafeInsetLeft());
+ assertEquals(2, mCutoutNumbers.getSafeInsetTop());
+ assertEquals(3, mCutoutNumbers.getSafeInsetRight());
+ assertEquals(4, mCutoutNumbers.getSafeInsetBottom());
+
+ Rect safeInsets = new Rect();
+ mCutoutNumbers.getSafeInsets(safeInsets);
+
+ assertEquals(new Rect(1, 2, 3, 4), safeInsets);
+ }
+
+ @Test
+ public void getBoundingRect() throws Exception {
+ Rect boundingRect = new Rect();
+ mCutoutTop.getBoundingRect(boundingRect);
+
+ assertEquals(new Rect(50, 0, 75, 100), boundingRect);
+ }
+
+ @Test
+ public void getBoundingPolygon() throws Exception {
+ ArrayList<Point> boundingPolygon = new ArrayList<>();
+ mCutoutTop.getBoundingPolygon(boundingPolygon);
+
+ assertEquals(Arrays.asList(
+ new Point(75, 0),
+ new Point(50, 0),
+ new Point(75, 100),
+ new Point(50, 100)), boundingPolygon);
+ }
+
+ @Test
+ public void testHashCode() throws Exception {
+ assertEquals(mCutoutTop.hashCode(), createCutoutTop().hashCode());
+ assertNotEquals(mCutoutTop.hashCode(), mCutoutNumbers.hashCode());
+ }
+
+ @Test
+ public void testEquals() throws Exception {
+ assertEquals(mCutoutTop, createCutoutTop());
+ assertNotEquals(mCutoutTop, mCutoutNumbers);
+ }
+
+ @Test
+ public void testToString() throws Exception {
+ assertFalse(mCutoutTop.toString().isEmpty());
+ assertFalse(mCutoutNumbers.toString().isEmpty());
+ }
+
+ @Test
+ public void inset_immutable() throws Exception {
+ DisplayCutout cutout = mCutoutTop.inset(1, 2, 3, 4);
+
+ assertEquals("original instance must not be mutated", createCutoutTop(), mCutoutTop);
+ }
+
+ @Test
+ public void inset_insets_withLeftCutout() throws Exception {
+ DisplayCutout cutout = createCutoutWithInsets(100, 0, 0, 0).inset(1, 2, 3, 4);
+
+ assertEquals(cutout.getSafeInsetLeft(), 99);
+ assertEquals(cutout.getSafeInsetTop(), 0);
+ assertEquals(cutout.getSafeInsetRight(), 0);
+ assertEquals(cutout.getSafeInsetBottom(), 0);
+ }
+
+ @Test
+ public void inset_insets_withTopCutout() throws Exception {
+ DisplayCutout cutout = mCutoutTop.inset(1, 2, 3, 4);
+
+ assertEquals(cutout.getSafeInsetLeft(), 0);
+ assertEquals(cutout.getSafeInsetTop(), 98);
+ assertEquals(cutout.getSafeInsetRight(), 0);
+ assertEquals(cutout.getSafeInsetBottom(), 0);
+ }
+
+ @Test
+ public void inset_insets_withRightCutout() throws Exception {
+ DisplayCutout cutout = createCutoutWithInsets(0, 0, 100, 0).inset(1, 2, 3, 4);
+
+ assertEquals(cutout.getSafeInsetLeft(), 0);
+ assertEquals(cutout.getSafeInsetTop(), 0);
+ assertEquals(cutout.getSafeInsetRight(), 97);
+ assertEquals(cutout.getSafeInsetBottom(), 0);
+ }
+
+ @Test
+ public void inset_insets_withBottomCutout() throws Exception {
+ DisplayCutout cutout = createCutoutWithInsets(0, 0, 0, 100).inset(1, 2, 3, 4);
+
+ assertEquals(cutout.getSafeInsetLeft(), 0);
+ assertEquals(cutout.getSafeInsetTop(), 0);
+ assertEquals(cutout.getSafeInsetRight(), 0);
+ assertEquals(cutout.getSafeInsetBottom(), 96);
+ }
+
+ @Test
+ public void inset_insets_consumeInset() throws Exception {
+ DisplayCutout cutout = mCutoutTop.inset(0, 1000, 0, 0);
+
+ assertEquals(cutout.getSafeInsetLeft(), 0);
+ assertEquals(cutout.getSafeInsetTop(), 0);
+ assertEquals(cutout.getSafeInsetRight(), 0);
+ assertEquals(cutout.getSafeInsetBottom(), 0);
+
+ assertFalse(cutout.hasCutout());
+ }
+
+ @Test
+ public void inset_bounds() throws Exception {
+ DisplayCutout cutout = mCutoutTop.inset(1, 2, 3, 4);
+
+ Rect boundingRect = new Rect();
+ cutout.getBoundingRect(boundingRect);
+
+ assertEquals(new Rect(49, -2, 74, 98), boundingRect);
+
+ ArrayList<Point> boundingPolygon = new ArrayList<>();
+ cutout.getBoundingPolygon(boundingPolygon);
+
+ assertEquals(Arrays.asList(
+ new Point(74, -2),
+ new Point(49, -2),
+ new Point(74, 98),
+ new Point(49, 98)), boundingPolygon);
+ }
+
+ @Test
+ public void calculateRelativeTo_top() throws Exception {
+ DisplayCutout cutout = mCutoutTop.calculateRelativeTo(new Rect(0, 0, 200, 400));
+
+ Rect insets = new Rect();
+ cutout.getSafeInsets(insets);
+
+ assertEquals(new Rect(0, 100, 0, 0), insets);
+ }
+
+ @Test
+ public void calculateRelativeTo_left() throws Exception {
+ DisplayCutout cutout = mCutoutTop.calculateRelativeTo(new Rect(0, 0, 400, 200));
+
+ Rect insets = new Rect();
+ cutout.getSafeInsets(insets);
+
+ assertEquals(new Rect(75, 0, 0, 0), insets);
+ }
+
+ @Test
+ public void calculateRelativeTo_bottom() throws Exception {
+ DisplayCutout cutout = mCutoutTop.calculateRelativeTo(new Rect(0, -300, 200, 100));
+
+ Rect insets = new Rect();
+ cutout.getSafeInsets(insets);
+
+ assertEquals(new Rect(0, 0, 0, 100), insets);
+ }
+
+ @Test
+ public void calculateRelativeTo_right() throws Exception {
+ DisplayCutout cutout = mCutoutTop.calculateRelativeTo(new Rect(-400, -200, 100, 100));
+
+ Rect insets = new Rect();
+ cutout.getSafeInsets(insets);
+
+ assertEquals(new Rect(0, 0, 50, 0), insets);
+ }
+
+ @Test
+ public void calculateRelativeTo_bounds() throws Exception {
+ DisplayCutout cutout = mCutoutTop.calculateRelativeTo(new Rect(-1000, -2000, 100, 200));
+
+
+ Rect boundingRect = new Rect();
+ cutout.getBoundingRect(boundingRect);
+ assertEquals(new Rect(1050, 2000, 1075, 2100), boundingRect);
+
+ ArrayList<Point> boundingPolygon = new ArrayList<>();
+ cutout.getBoundingPolygon(boundingPolygon);
+
+ assertEquals(Arrays.asList(
+ new Point(1075, 2000),
+ new Point(1050, 2000),
+ new Point(1075, 2100),
+ new Point(1050, 2100)), boundingPolygon);
+ }
+
+ @Test
+ public void fromBoundingPolygon() throws Exception {
+ assertEquals(
+ new DisplayCutout(
+ new Rect(0, 0, 0, 0), // fromBoundingPolygon won't calculate safe insets.
+ new Rect(50, 0, 75, 100),
+ Arrays.asList(
+ new Point(75, 0),
+ new Point(50, 0),
+ new Point(75, 100),
+ new Point(50, 100))),
+ DisplayCutout.fromBoundingPolygon(
+ Arrays.asList(
+ new Point(75, 0),
+ new Point(50, 0),
+ new Point(75, 100),
+ new Point(50, 100))));
+ }
+
+ @Test
+ public void parcel_unparcel_regular() {
+ Parcel p = Parcel.obtain();
+
+ new ParcelableWrapper(mCutoutTop).writeToParcel(p, 0);
+ int posAfterWrite = p.dataPosition();
+
+ p.setDataPosition(0);
+
+ assertEquals(mCutoutTop, ParcelableWrapper.CREATOR.createFromParcel(p).get());
+ assertEquals(posAfterWrite, p.dataPosition());
+ }
+
+ @Test
+ public void parcel_unparcel_nocutout() {
+ Parcel p = Parcel.obtain();
+
+ new ParcelableWrapper(NO_CUTOUT).writeToParcel(p, 0);
+ int posAfterWrite = p.dataPosition();
+
+ p.setDataPosition(0);
+
+ assertEquals(NO_CUTOUT, ParcelableWrapper.CREATOR.createFromParcel(p).get());
+ assertEquals(posAfterWrite, p.dataPosition());
+ }
+
+ @Test
+ public void parcel_unparcel_inplace() {
+ Parcel p = Parcel.obtain();
+
+ new ParcelableWrapper(mCutoutTop).writeToParcel(p, 0);
+ int posAfterWrite = p.dataPosition();
+
+ p.setDataPosition(0);
+
+ ParcelableWrapper wrapper = new ParcelableWrapper();
+ wrapper.readFromParcel(p);
+
+ assertEquals(mCutoutTop, wrapper.get());
+ assertEquals(posAfterWrite, p.dataPosition());
+ }
+
+ @Test
+ public void wrapper_hashcode() throws Exception {
+ assertEquals(new ParcelableWrapper(mCutoutTop).hashCode(),
+ new ParcelableWrapper(createCutoutTop()).hashCode());
+ assertNotEquals(new ParcelableWrapper(mCutoutTop).hashCode(),
+ new ParcelableWrapper(mCutoutNumbers).hashCode());
+ }
+
+ @Test
+ public void wrapper_equals() throws Exception {
+ assertEquals(new ParcelableWrapper(mCutoutTop), new ParcelableWrapper(createCutoutTop()));
+ assertNotEquals(new ParcelableWrapper(mCutoutTop), new ParcelableWrapper(mCutoutNumbers));
+ }
+
+ private static DisplayCutout createCutoutTop() {
+ return new DisplayCutout(
+ new Rect(0, 100, 0, 0),
+ new Rect(50, 0, 75, 100),
+ Arrays.asList(
+ new Point(75, 0),
+ new Point(50, 0),
+ new Point(75, 100),
+ new Point(50, 100)));
+ }
+
+ private static DisplayCutout createCutoutWithInsets(int left, int top, int right, int bottom) {
+ return new DisplayCutout(
+ new Rect(left, top, right, bottom),
+ new Rect(50, 0, 75, 100),
+ Arrays.asList(
+ new Point(75, 0),
+ new Point(50, 0),
+ new Point(75, 100),
+ new Point(50, 100)));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
similarity index 95%
rename from services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java
rename to core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
index c8dc9ff..2f32d13 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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,26 +14,23 @@
* limitations under the License.
*/
-package com.android.server.accessibility;
+package android.view.accessibility;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
+
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.support.test.runner.AndroidJUnit4;
-import android.view.accessibility.AccessibilityCache;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityInteractionClient;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityWindowInfo;
import android.view.View;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -48,27 +45,27 @@
@RunWith(AndroidJUnit4.class)
public class AccessibilityCacheTest {
- private static int WINDOW_ID_1 = 0xBEEF;
- private static int WINDOW_ID_2 = 0xFACE;
- private static int SINGLE_VIEW_ID = 0xCAFE;
- private static int OTHER_VIEW_ID = 0xCAB2;
- private static int PARENT_VIEW_ID = 0xFED4;
- private static int CHILD_VIEW_ID = 0xFEED;
- private static int OTHER_CHILD_VIEW_ID = 0xACE2;
- private static int MOCK_CONNECTION_ID = 1;
+ private static final int WINDOW_ID_1 = 0xBEEF;
+ private static final int WINDOW_ID_2 = 0xFACE;
+ private static final int SINGLE_VIEW_ID = 0xCAFE;
+ private static final int OTHER_VIEW_ID = 0xCAB2;
+ private static final int PARENT_VIEW_ID = 0xFED4;
+ private static final int CHILD_VIEW_ID = 0xFEED;
+ private static final int OTHER_CHILD_VIEW_ID = 0xACE2;
+ private static final int MOCK_CONNECTION_ID = 1;
AccessibilityCache mAccessibilityCache;
AccessibilityCache.AccessibilityNodeRefresher mAccessibilityNodeRefresher;
- AtomicInteger numA11yNodeInfosInUse = new AtomicInteger(0);
- AtomicInteger numA11yWinInfosInUse = new AtomicInteger(0);
+ AtomicInteger mNumA11yNodeInfosInUse = new AtomicInteger(0);
+ AtomicInteger mNumA11yWinInfosInUse = new AtomicInteger(0);
@Before
public void setUp() {
mAccessibilityNodeRefresher = mock(AccessibilityCache.AccessibilityNodeRefresher.class);
when(mAccessibilityNodeRefresher.refreshNode(anyObject(), anyBoolean())).thenReturn(true);
mAccessibilityCache = new AccessibilityCache(mAccessibilityNodeRefresher);
- AccessibilityNodeInfo.setNumInstancesInUseCounter(numA11yNodeInfosInUse);
- AccessibilityWindowInfo.setNumInstancesInUseCounter(numA11yWinInfosInUse);
+ AccessibilityNodeInfo.setNumInstancesInUseCounter(mNumA11yNodeInfosInUse);
+ AccessibilityWindowInfo.setNumInstancesInUseCounter(mNumA11yWinInfosInUse);
}
@After
@@ -76,7 +73,8 @@
// Make sure we're recycling all of our window and node infos
mAccessibilityCache.clear();
AccessibilityInteractionClient.getInstance().clearCache();
- assertEquals(0, numA11yWinInfosInUse.get());
+ assertEquals(0, mNumA11yWinInfosInUse.get());
+ assertEquals(0, mNumA11yNodeInfosInUse.get());
}
@Test
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
new file mode 100644
index 0000000..8a5fc2d
--- /dev/null
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 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 android.view.accessibility;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests for AccessibilityInteractionClient
+ */
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityInteractionClientTest {
+ private static final int MOCK_CONNECTION_ID = 0xabcd;
+
+ private MockConnection mMockConnection = new MockConnection();
+ @Mock private AccessibilityCache mMockCache;
+
+ @Before
+ public void setUp() {
+ initMocks(this);
+ AccessibilityInteractionClient.setCache(mMockCache);
+ AccessibilityInteractionClient.addConnection(MOCK_CONNECTION_ID, mMockConnection);
+ }
+
+ /**
+ * When the AccessibilityCache refreshes the nodes it contains, it gets very confused if
+ * it is called to update itself during the refresh. It tries to update the node that it's
+ * in the process of refreshing, which leads to AccessibilityNodeInfos in inconsistent states.
+ */
+ @Test
+ public void findA11yNodeInfoByA11yId_whenBypassingCache_doesntTouchCache() {
+ final int windowId = 0x1234;
+ final long accessibilityNodeId = 0x4321L;
+ AccessibilityNodeInfo nodeFromConnection = AccessibilityNodeInfo.obtain();
+ nodeFromConnection.setSourceNodeId(accessibilityNodeId, windowId);
+ mMockConnection.mInfosToReturn = Arrays.asList(nodeFromConnection);
+ AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
+ AccessibilityNodeInfo node = client.findAccessibilityNodeInfoByAccessibilityId(
+ MOCK_CONNECTION_ID, windowId, accessibilityNodeId, true, 0, null);
+ assertEquals("Node got lost along the way", nodeFromConnection, node);
+
+ verifyZeroInteractions(mMockCache);
+ }
+
+ private static class MockConnection extends AccessibilityServiceConnectionImpl {
+ List<AccessibilityNodeInfo> mInfosToReturn;
+
+ @Override
+ public boolean findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
+ long accessibilityNodeId, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
+ Bundle arguments) {
+ try {
+ callback.setFindAccessibilityNodeInfosResult(mInfosToReturn, interactionId);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ return true;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
similarity index 78%
rename from services/tests/servicestests/src/com/android/server/accessibility/AccessibilityNodeInfoTest.java
rename to core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
index 7f97973..79e6316 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityNodeInfoTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
@@ -1,10 +1,25 @@
-package com.android.server.accessibility;
+/*
+ * Copyright 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 android.view.accessibility;
import static org.junit.Assert.fail;
import android.support.test.runner.AndroidJUnit4;
import android.util.ArraySet;
-import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import com.android.internal.util.CollectionUtils;
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
new file mode 100644
index 0000000..d3bbee7
--- /dev/null
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 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 android.view.accessibility;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.IAccessibilityServiceConnection;
+import android.content.pm.ParceledListSlice;
+import android.graphics.Region;
+import android.os.Bundle;
+
+import java.util.List;
+
+/**
+ * Stub implementation of IAccessibilityServiceConnection so each test doesn't need to implement
+ * all of the methods
+ */
+public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceConnection.Stub {
+ public void setServiceInfo(AccessibilityServiceInfo info) {}
+
+ public boolean findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
+ long accessibilityNodeId, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
+ Bundle arguments) {
+ return false;
+ }
+
+ public boolean findAccessibilityNodeInfosByText(int accessibilityWindowId,
+ long accessibilityNodeId, String text, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback, long threadId) {
+ return false;
+ }
+
+ public boolean findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
+ long accessibilityNodeId, String viewId, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback, long threadId) {
+ return false;
+ }
+
+ public boolean findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType,
+ int interactionId, IAccessibilityInteractionConnectionCallback callback,
+ long threadId) {
+ return false;
+ }
+
+ public boolean focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction,
+ int interactionId, IAccessibilityInteractionConnectionCallback callback,
+ long threadId) {
+ return false;
+ }
+
+ public boolean performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId,
+ int action, Bundle arguments, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback, long threadId) {
+ return false;
+ }
+
+ public AccessibilityWindowInfo getWindow(int windowId) {
+ return null;
+ }
+
+ public List<AccessibilityWindowInfo> getWindows() {
+ return null;
+ }
+
+ public AccessibilityServiceInfo getServiceInfo() {
+ return null;
+ }
+
+ public boolean performGlobalAction(int action) {
+ return false;
+ }
+
+ public void disableSelf() {}
+
+ public void setOnKeyEventResult(boolean handled, int sequence) {}
+
+ public float getMagnificationScale() {
+ return 0.0f;
+ }
+
+ public float getMagnificationCenterX() {
+ return 0.0f;
+ }
+
+ public float getMagnificationCenterY() {
+ return 0.0f;
+ }
+
+ public Region getMagnificationRegion() {
+ return null;
+ }
+
+ public boolean resetMagnification(boolean animate) {
+ return false;
+ }
+
+ public boolean setMagnificationScaleAndCenter(float scale, float centerX, float centerY,
+ boolean animate) {
+ return false;
+ }
+
+ public void setMagnificationCallbackEnabled(boolean enabled) {}
+
+ public boolean setSoftKeyboardShowMode(int showMode) {
+ return false;
+ }
+
+ public void setSoftKeyboardCallbackEnabled(boolean enabled) {}
+
+ public boolean isAccessibilityButtonAvailable() {
+ return false;
+ }
+
+ public void sendGesture(int sequence, ParceledListSlice gestureSteps) {}
+
+ public boolean isFingerprintGestureDetectionAvailable() {
+ return false;
+ }
+}
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
index 13cef52..e3c91e6 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
@@ -68,6 +68,17 @@
assertThat(clone.supportsSwitchingToNextInputMethod(), is(true));
}
+ @Test
+ public void testIsVrOnly() throws Exception {
+ final InputMethodInfo imi = buildInputMethodForTest(R.xml.ime_meta_vr_only);
+
+ assertThat(imi.isVrOnly(), is(true));
+
+ final InputMethodInfo clone = cloneViaParcel(imi);
+
+ assertThat(clone.isVrOnly(), is(true));
+ }
+
private InputMethodInfo buildInputMethodForTest(final @XmlRes int metaDataRes)
throws Exception {
final Context context = InstrumentationRegistry.getContext();
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 41686fa..9092c85 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -45,6 +45,9 @@
private TextClassificationManager mTcm;
private TextClassifier mClassifier;
+ private TextSelection.Options mSelectionOptions;
+ private TextClassification.Options mClassificationOptions;
+ private TextLinks.Options mLinksOptions;
@Before
public void setup() {
@@ -52,6 +55,9 @@
.getSystemService(TextClassificationManager.class);
mTcm.setTextClassifier(null);
mClassifier = mTcm.getTextClassifier();
+ mSelectionOptions = new TextSelection.Options().setDefaultLocales(LOCALES);
+ mClassificationOptions = new TextClassification.Options().setDefaultLocales(LOCALES);
+ mLinksOptions = new TextLinks.Options().setDefaultLocales(LOCALES);
}
@Test
@@ -66,24 +72,9 @@
int smartStartIndex = text.indexOf(suggested);
int smartEndIndex = smartStartIndex + suggested.length();
- assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES),
- isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_EMAIL));
- }
-
- @Test
- public void testSmartSelection_nullLocaleList() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Contact me at droid@android.com";
- String selected = "droid";
- String suggested = "droid@android.com";
- int startIndex = text.indexOf(selected);
- int endIndex = startIndex + selected.length();
- int smartStartIndex = text.indexOf(suggested);
- int smartEndIndex = smartStartIndex + suggested.length();
- LocaleList nullLocales = null;
-
- assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, nullLocales),
+ TextSelection selection = mClassifier.suggestSelection(
+ text, startIndex, endIndex, mSelectionOptions);
+ assertThat(selection,
isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_EMAIL));
}
@@ -99,7 +90,9 @@
int smartStartIndex = text.indexOf(suggested);
int smartEndIndex = smartStartIndex + suggested.length();
- assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES),
+ TextSelection selection = mClassifier.suggestSelection(
+ text, startIndex, endIndex, mSelectionOptions);
+ assertThat(selection,
isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_URL));
}
@@ -112,7 +105,9 @@
int startIndex = text.indexOf(selected);
int endIndex = startIndex + selected.length();
- assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES),
+ TextSelection selection = mClassifier.suggestSelection(
+ text, startIndex, endIndex, mSelectionOptions);
+ assertThat(selection,
isTextSelection(startIndex, endIndex, NO_TYPE));
}
@@ -124,7 +119,10 @@
String classifiedText = "droid@android.com";
int startIndex = text.indexOf(classifiedText);
int endIndex = startIndex + classifiedText.length();
- assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
+
+ TextClassification classification = mClassifier.classifyText(
+ text, startIndex, endIndex, mClassificationOptions);
+ assertThat(classification,
isTextClassification(
classifiedText,
TextClassifier.TYPE_EMAIL,
@@ -139,7 +137,10 @@
String classifiedText = "www.android.com";
int startIndex = text.indexOf(classifiedText);
int endIndex = startIndex + classifiedText.length();
- assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
+
+ TextClassification classification = mClassifier.classifyText(
+ text, startIndex, endIndex, mClassificationOptions);
+ assertThat(classification,
isTextClassification(
classifiedText,
TextClassifier.TYPE_URL,
@@ -154,7 +155,10 @@
String classifiedText = "HTTP://ANDROID.COM";
int startIndex = text.indexOf(classifiedText);
int endIndex = startIndex + classifiedText.length();
- assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
+
+ TextClassification classification = mClassifier.classifyText(
+ text, startIndex, endIndex, mClassificationOptions);
+ assertThat(classification,
isTextClassification(
classifiedText,
TextClassifier.TYPE_URL,
@@ -162,22 +166,6 @@
}
@Test
- public void testTextClassifyText_nullLocaleList() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Contact me at droid@android.com";
- String classifiedText = "droid@android.com";
- int startIndex = text.indexOf(classifiedText);
- int endIndex = startIndex + classifiedText.length();
- LocaleList nullLocales = null;
- assertThat(mClassifier.classifyText(text, startIndex, endIndex, nullLocales),
- isTextClassification(
- classifiedText,
- TextClassifier.TYPE_EMAIL,
- "mailto:" + classifiedText));
- }
-
- @Test
public void testGenerateLinks() {
if (isTextClassifierDisabled()) return;
@@ -210,13 +198,14 @@
int startIndex = text.indexOf(classifiedText);
int endIndex = startIndex + classifiedText.length();
- Collection<TextLinks.TextLink> links = mClassifier.generateLinks(text, null).getLinks();
+ Collection<TextLinks.TextLink> links = mClassifier.generateLinks(text, mLinksOptions)
+ .getLinks();
for (TextLinks.TextLink link : links) {
if (text.subSequence(link.getStart(), link.getEnd()).equals(classifiedText)) {
assertEquals(type, link.getEntity(0));
assertEquals(startIndex, link.getStart());
assertEquals(endIndex, link.getEnd());
- assertTrue(link.getConfidenceScore(type) > .9);
+ assertTrue(link.getConfidenceScore(type) > 0);
return;
}
}
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index d31da71..7875c17 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -204,7 +204,7 @@
int lineCount = layout.getLineCount();
boolean hyphenationHappend = false;
for (int i = 0; i < lineCount; ++i) {
- if (layout.getHyphen(i) != 1) {
+ if (layout.getHyphen(i) == 0) {
continue; // Hyphantion does not happen.
}
hyphenationHappend = true;
diff --git a/services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
similarity index 88%
rename from services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java
rename to core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index a4e3988..449e374 100644
--- a/services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.policy;
+package com.android.internal.accessibility;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.AlertDialog;
@@ -22,6 +22,7 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.os.Handler;
@@ -38,7 +39,7 @@
import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.policy.AccessibilityShortcutController.FrameworkObjectProvider;
+import com.android.internal.accessibility.AccessibilityShortcutController.FrameworkObjectProvider;
import org.junit.After;
import org.junit.Before;
@@ -50,6 +51,7 @@
import java.lang.reflect.Field;
import java.util.Collections;
+import java.util.Map;
import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN;
import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED;
@@ -58,7 +60,10 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.fail;
import static org.mockito.AdditionalMatchers.aryEq;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyObject;
@@ -72,6 +77,7 @@
@RunWith(AndroidJUnit4.class)
public class AccessibilityShortcutControllerTest {
private static final String SERVICE_NAME_STRING = "fake.package/fake.service.name";
+ private static final String SERVICE_NAME_SUMMARY = "Summary";
private static final long VIBRATOR_PATTERN_1 = 100L;
private static final long VIBRATOR_PATTERN_2 = 150L;
private static final int[] VIBRATOR_PATTERN_INT = {(int) VIBRATOR_PATTERN_1,
@@ -95,6 +101,7 @@
private @Mock Toast mToast;
private @Mock Vibrator mVibrator;
private @Mock ApplicationInfo mApplicationInfo;
+ private @Mock PackageManager mPackageManager;
private MockContentResolver mContentResolver;
private WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams();
@@ -108,6 +115,10 @@
when(mContext.getResources()).thenReturn(mResources);
when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo);
when(mContext.getSystemService(Context.VIBRATOR_SERVICE)).thenReturn(mVibrator);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+
+ // We're not checking the text. Just prevent us crashing when getting text.
+ when(mPackageManager.getText(any(), anyInt(), any())).thenReturn("text");
mContentResolver = new MockContentResolver(mContext);
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
@@ -125,6 +136,7 @@
.thenReturn(mAlertDialogBuilder);
when(mFrameworkObjectProvider.makeToastFromText(eq(mContext), anyObject(), anyInt()))
.thenReturn(mToast);
+ when(mFrameworkObjectProvider.getSystemUiContext()).thenReturn(mContext);
when(mResources.getString(anyInt())).thenReturn("Howdy %s");
when(mResources.getIntArray(anyInt())).thenReturn(VIBRATOR_PATTERN_INT);
@@ -134,6 +146,7 @@
when(mServiceInfo.getResolveInfo()).thenReturn(resolveInfo);
when(mServiceInfo.getComponentName())
.thenReturn(ComponentName.unflattenFromString(SERVICE_NAME_STRING));
+ when(mServiceInfo.loadSummary(any())).thenReturn(SERVICE_NAME_SUMMARY);
when(mAlertDialogBuilder.setTitle(anyInt())).thenReturn(mAlertDialogBuilder);
when(mAlertDialogBuilder.setCancelable(anyBoolean())).thenReturn(mAlertDialogBuilder);
@@ -369,6 +382,33 @@
verify(mAccessibilityManagerService).performAccessibilityShortcut();
}
+ @Test
+ public void getFrameworkFeatureMap_shouldBeNonNullAndUnmodifiable() {
+ Map<ComponentName, AccessibilityShortcutController.ToggleableFrameworkFeatureInfo>
+ frameworkFeatureMap =
+ AccessibilityShortcutController.getFrameworkShortcutFeaturesMap();
+ assertTrue("Framework features not supported", frameworkFeatureMap.size() > 0);
+
+ try {
+ frameworkFeatureMap.clear();
+ fail("Framework feature map should be unmodifieable");
+ } catch (UnsupportedOperationException e) {
+ // Expected
+ }
+ }
+
+ @Test
+ public void testOnAccessibilityShortcut_forFrameworkFeature_callsServiceWithNoToast()
+ throws Exception {
+ configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+ configureFirstFrameworkFeature();
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1);
+ getController().performAccessibilityShortcut();
+
+ verifyZeroInteractions(mToast);
+ verify(mAccessibilityManagerService).performAccessibilityShortcut();
+ }
+
private void configureNoShortcutService() {
Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "");
}
@@ -378,6 +418,14 @@
mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, SERVICE_NAME_STRING);
}
+ private void configureFirstFrameworkFeature() {
+ ComponentName featureComponentName =
+ (ComponentName) AccessibilityShortcutController.getFrameworkShortcutFeaturesMap()
+ .keySet().toArray()[0];
+ Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+ featureComponentName.flattenToString());
+ }
+
private void configureShortcutEnabled(int enabledValue) {
final boolean enabled;
final boolean lockscreen;
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 55e804b..9fcb06e 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -18,6 +18,7 @@
import com.android.internal.R;
import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
+import com.android.internal.widget.ResolverDrawerLayout;
import org.junit.Before;
import org.junit.Rule;
@@ -33,6 +34,8 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.widget.RelativeLayout;
import java.util.ArrayList;
import java.util.List;
@@ -100,6 +103,34 @@
}
@Test
+ public void setShowAtTopToTrue() throws Exception {
+ Intent sendIntent = createSendImageIntent();
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+ waitForIdle();
+
+ final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+ final View resolverList = activity.findViewById(R.id.resolver_list);
+ final RelativeLayout profileView =
+ (RelativeLayout) activity.findViewById(R.id.profile_button).getParent();
+ assertThat("Drawer should show at bottom by default",
+ profileView.getBottom() == resolverList.getTop() && profileView.getTop() > 0);
+
+ activity.runOnUiThread(() -> {
+ ResolverDrawerLayout layout = (ResolverDrawerLayout)
+ activity.findViewById(
+ R.id.contentPanel);
+ layout.setShowAtTop(true);
+ });
+ waitForIdle();
+ assertThat("Drawer should show at top with new attribute",
+ profileView.getBottom() == resolverList.getTop() && profileView.getTop() == 0);
+ }
+
+ @Test
public void hasLastChosenActivity() throws Exception {
Intent sendIntent = createSendImageIntent();
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -283,4 +314,4 @@
private void waitForIdle() {
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
-}
\ No newline at end of file
+}
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
index 515e558..9061c44 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
@@ -38,6 +38,7 @@
private static final String DUMMY_SETTING_ACTIVITY_NAME = "";
private static final boolean DUMMY_IS_AUX_IME = false;
private static final boolean DUMMY_FORCE_DEFAULT = false;
+ private static final boolean DUMMY_IS_VR_IME = false;
private static final int DUMMY_IS_DEFAULT_RES_ID = 0;
private static final String SYSTEM_LOCALE = "en_US";
private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
@@ -75,7 +76,7 @@
}
final InputMethodInfo imi = new InputMethodInfo(ri, DUMMY_IS_AUX_IME,
DUMMY_SETTING_ACTIVITY_NAME, subtypes, DUMMY_IS_DEFAULT_RES_ID,
- DUMMY_FORCE_DEFAULT, supportsSwitchingToNextInputMethod);
+ DUMMY_FORCE_DEFAULT, supportsSwitchingToNextInputMethod, DUMMY_IS_VR_IME);
if (subtypes == null) {
items.add(new ImeSubtypeListItem(imeName, null /* variableName */, imi,
NOT_A_SUBTYPE_ID, null, SYSTEM_LOCALE));
@@ -111,7 +112,8 @@
.build());
final InputMethodInfo imi = new InputMethodInfo(ri, DUMMY_IS_AUX_IME,
DUMMY_SETTING_ACTIVITY_NAME, subtypes, DUMMY_IS_DEFAULT_RES_ID,
- DUMMY_FORCE_DEFAULT, true /* supportsSwitchingToNextInputMethod */);
+ DUMMY_FORCE_DEFAULT, true /* supportsSwitchingToNextInputMethod */,
+ DUMMY_IS_VR_IME);
return new ImeSubtypeListItem(imeName, subtypeName, imi, subtypeIndex, subtypeLocale,
systemLocale);
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
new file mode 100644
index 0000000..4b197e4
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -0,0 +1,405 @@
+/*
+ * 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.internal.os;
+
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import static org.junit.Assume.assumeTrue;
+
+import com.android.frameworks.coretests.aidl.ICmdCallback;
+import com.android.frameworks.coretests.aidl.ICmdReceiver;
+
+import android.app.KeyguardManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.os.BatteryManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.UiDevice;
+import android.util.Log;
+
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class BstatsCpuTimesValidationTest {
+ private static final String TAG = BstatsCpuTimesValidationTest.class.getName();
+
+ private static final String TEST_PKG = "com.android.coretests.apps.bstatstestapp";
+ private static final String TEST_ACTIVITY = TEST_PKG + ".TestActivity";
+ private static final String ISOLATED_TEST_SERVICE = TEST_PKG + ".IsolatedTestService";
+
+ private static final String EXTRA_KEY_CMD_RECEIVER = "cmd_receiver";
+
+ private static final int BATTERY_STATE_TIMEOUT_MS = 2000;
+ private static final int BATTERY_STATE_CHECK_INTERVAL_MS = 200;
+
+ private static final int START_ACTIVITY_TIMEOUT_MS = 2000;
+ private static final int START_ISOLATED_SERVICE_TIMEOUT_MS = 2000;
+
+ private static final int GENERAL_TIMEOUT_MS = 1000;
+ private static final int GENERAL_INTERVAL_MS = 100;
+
+ private static final int WORK_DURATION_MS = 2000;
+
+ private static Context sContext;
+ private static UiDevice sUiDevice;
+ private static int sTestPkgUid;
+ private static boolean sCpuFreqTimesAvailable;
+
+ @BeforeClass
+ public static void setupOnce() throws Exception {
+ sContext = InstrumentationRegistry.getContext();
+ sUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ sContext.getPackageManager().setApplicationEnabledSetting(TEST_PKG,
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
+ sTestPkgUid = sContext.getPackageManager().getPackageUid(TEST_PKG, 0);
+ sCpuFreqTimesAvailable = cpuFreqTimesAvailable();
+ }
+
+ // Checks cpu freq times of system uid as an indication of whether /proc/uid_time_in_state
+ // kernel node is available.
+ private static boolean cpuFreqTimesAvailable() throws Exception {
+ final long[] cpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID);
+ return cpuTimes != null;
+ }
+
+ @Test
+ public void testCpuFreqTimes() throws Exception {
+ if (!sCpuFreqTimesAvailable) {
+ return;
+ }
+
+ batteryOnScreenOn();
+ forceStop();
+ resetBatteryStats();
+ final long[] initialSnapshot = getAllCpuFreqTimes(sTestPkgUid);
+ assertNull("Initial snapshot should be null", initialSnapshot);
+ doSomeWork();
+ forceStop();
+
+ final long[] cpuTimesMs = getAllCpuFreqTimes(sTestPkgUid);
+ assertCpuTimesValid(cpuTimesMs);
+ long actualCpuTimeMs = 0;
+ for (int i = 0; i < cpuTimesMs.length / 2; ++i) {
+ actualCpuTimeMs += cpuTimesMs[i];
+ }
+ assertApproximateValue("Incorrect total cpu time", WORK_DURATION_MS, actualCpuTimeMs);
+ batteryOffScreenOn();
+ }
+
+ @Test
+ public void testCpuFreqTimes_screenOff() throws Exception {
+ if (!sCpuFreqTimesAvailable) {
+ return;
+ }
+
+ batteryOnScreenOff();
+ forceStop();
+ resetBatteryStats();
+ final long[] initialSnapshot = getAllCpuFreqTimes(sTestPkgUid);
+ assertNull("Initial snapshot should be null", initialSnapshot);
+ doSomeWork();
+ forceStop();
+
+ final long[] cpuTimesMs = getAllCpuFreqTimes(sTestPkgUid);
+ assertCpuTimesValid(cpuTimesMs);
+ long actualTotalCpuTimeMs = 0;
+ for (int i = 0; i < cpuTimesMs.length / 2; ++i) {
+ actualTotalCpuTimeMs += cpuTimesMs[i];
+ }
+ assertApproximateValue("Incorrect total cpu time", WORK_DURATION_MS, actualTotalCpuTimeMs);
+ long actualScreenOffCpuTimeMs = 0;
+ for (int i = cpuTimesMs.length / 2; i < cpuTimesMs.length; ++i) {
+ actualScreenOffCpuTimeMs += cpuTimesMs[i];
+ }
+ assertApproximateValue("Incorrect screen-off cpu time",
+ WORK_DURATION_MS, actualScreenOffCpuTimeMs);
+ batteryOffScreenOn();
+ }
+
+ @Test
+ public void testCpuFreqTimes_isolatedProcess() throws Exception {
+ if (!sCpuFreqTimesAvailable) {
+ return;
+ }
+
+ batteryOnScreenOn();
+ forceStop();
+ resetBatteryStats();
+ final long[] initialSnapshot = getAllCpuFreqTimes(sTestPkgUid);
+ assertNull("Initial snapshot should be null", initialSnapshot);
+ doSomeWorkInIsolatedProcess();
+ forceStop();
+
+ final long[] cpuTimesMs = getAllCpuFreqTimes(sTestPkgUid);
+ assertCpuTimesValid(cpuTimesMs);
+ long actualCpuTimeMs = 0;
+ for (int i = 0; i < cpuTimesMs.length / 2; ++i) {
+ actualCpuTimeMs += cpuTimesMs[i];
+ }
+ assertApproximateValue("Incorrect total cpu time", WORK_DURATION_MS, actualCpuTimeMs);
+ batteryOffScreenOn();
+ }
+
+ private void assertCpuTimesValid(long[] cpuTimes) {
+ assertNotNull(cpuTimes);
+ for (int i = 0; i < cpuTimes.length; ++i) {
+ if (cpuTimes[i] < 0) {
+ fail("Malformed cpu times data (-ve values): " + Arrays.toString(cpuTimes));
+ }
+ }
+ final int numFreqs = cpuTimes.length / 2;
+ for (int i = 0; i < numFreqs; ++i) {
+ if (cpuTimes[i] < cpuTimes[numFreqs + i]) {
+ fail("Malformed cpu times data (screen-off > total)" + Arrays.toString(cpuTimes));
+ }
+ }
+ }
+
+ private void assertApproximateValue(String errorPrefix, long expectedValue, long actualValue) {
+ assertValueRange(errorPrefix, actualValue, expectedValue * 0.5, expectedValue * 1.5);
+ }
+
+ private void assertValueRange(String errorPrefix,
+ long actualvalue, double minValue, double maxValue) {
+ final String errorMsg = String.format(errorPrefix + "; actual=%s; min=%s; max=%s",
+ actualvalue, minValue, maxValue);
+ assertTrue(errorMsg, actualvalue < maxValue);
+ assertTrue(errorMsg, actualvalue > minValue);
+ }
+
+ private void doSomeWork() throws Exception {
+ final ICmdReceiver receiver = ICmdReceiver.Stub.asInterface(startActivity());
+ receiver.doSomeWork(WORK_DURATION_MS);
+ receiver.finishHost();
+ }
+
+ private void doSomeWorkInIsolatedProcess() throws Exception {
+ final ICmdReceiver receiver = ICmdReceiver.Stub.asInterface(startIsolatedService());
+ receiver.doSomeWork(WORK_DURATION_MS);
+ receiver.finishHost();
+ }
+
+ private IBinder startIsolatedService() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final IBinder[] binders = new IBinder[1];
+ final ServiceConnection connection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ binders[0] = service;
+ latch.countDown();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ }
+ };
+ final Intent launchIntent = new Intent()
+ .setComponent(new ComponentName(TEST_PKG, ISOLATED_TEST_SERVICE));
+ sContext.bindService(launchIntent, connection, Context.BIND_AUTO_CREATE
+ | Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_FOREGROUND);
+ if (latch.await(START_ISOLATED_SERVICE_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ if (binders[0] == null) {
+ fail("Receiver binder should not be null");
+ }
+ return binders[0];
+ } else {
+ fail("Timed out waiting for the isolated test service to start");
+ }
+ return null;
+ }
+
+ private IBinder startActivity() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final Intent launchIntent = new Intent()
+ .setComponent(new ComponentName(TEST_PKG, TEST_ACTIVITY));
+ final Bundle extras = new Bundle();
+ final IBinder[] binders = new IBinder[1];
+ extras.putBinder(EXTRA_KEY_CMD_RECEIVER, new ICmdCallback.Stub() {
+ @Override
+ public void onActivityLaunched(IBinder receiver) {
+ binders[0] = receiver;
+ latch.countDown();
+ }
+ });
+ launchIntent.putExtras(extras);
+ sContext.startActivity(launchIntent);
+ if (latch.await(START_ACTIVITY_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ if (binders[0] == null) {
+ fail("Receiver binder should not be null");
+ }
+ return binders[0];
+ } else {
+ fail("Timed out waiting for the test activity to start; testUid=" + sTestPkgUid);
+ }
+ return null;
+ }
+
+ private static long[] getAllCpuFreqTimes(int uid) throws Exception {
+ final String checkinDump = executeCmdSilent("dumpsys batterystats --checkin");
+ final Pattern pattern = Pattern.compile(uid + ",l,ctf,A,(.*?)\n");
+ final Matcher matcher = pattern.matcher(checkinDump);
+ if (!matcher.find()) {
+ return null;
+ }
+ final String[] uidTimesStr = matcher.group(1).split(",");
+ final int freqCount = Integer.parseInt(uidTimesStr[0]);
+ if (uidTimesStr.length != (2 * freqCount + 1)) {
+ fail("Malformed data: " + Arrays.toString(uidTimesStr));
+ }
+ final long[] cpuTimes = new long[freqCount * 2];
+ for (int i = 0; i < cpuTimes.length; ++i) {
+ cpuTimes[i] = Long.parseLong(uidTimesStr[i + 1]);
+ }
+ return cpuTimes;
+ }
+
+ private void resetBatteryStats() throws Exception {
+ executeCmd("dumpsys batterystats --reset");
+ }
+
+ private void batteryOnScreenOn() throws Exception {
+ batteryOn();
+ screenOn();
+ }
+
+ private void batteryOnScreenOff() throws Exception {
+ batteryOn();
+ screenoff();
+ }
+
+ private void batteryOffScreenOn() throws Exception {
+ batteryOff();
+ screenOn();
+ }
+
+ private void batteryOn() throws Exception {
+ executeCmd("dumpsys battery unplug");
+ assertBatteryState(false);
+ }
+
+ private void batteryOff() throws Exception {
+ executeCmd("dumpsys battery reset");
+ assertBatteryState(true);
+ }
+
+ private void screenOn() throws Exception {
+ executeCmd("input keyevent KEYCODE_WAKEUP");
+ executeCmd("wm dismiss-keyguard");
+ assertKeyguardUnLocked();
+ assertScreenInteractive(true);
+ }
+
+ private void screenoff() throws Exception {
+ executeCmd("input keyevent KEYCODE_SLEEP");
+ assertScreenInteractive(false);
+ }
+
+ private void forceStop() throws Exception {
+ executeCmd("cmd activity force-stop " + TEST_PKG);
+ assertUidState(PROCESS_STATE_NONEXISTENT);
+ }
+
+ private void assertUidState(int state) throws Exception {
+ final String uidStateStr = executeCmd("cmd activity get-uid-state " + sTestPkgUid);
+ final int uidState = Integer.parseInt(uidStateStr.split(" ")[0]);
+ assertEquals(state, uidState);
+ }
+
+ private void assertKeyguardUnLocked() {
+ final KeyguardManager keyguardManager =
+ (KeyguardManager) sContext.getSystemService(Context.KEYGUARD_SERVICE);
+ assertDelayedCondition("Keyguard should be unlocked",
+ () -> !keyguardManager.isKeyguardLocked());
+ }
+
+ private void assertScreenInteractive(boolean interactive) {
+ final PowerManager powerManager =
+ (PowerManager) sContext.getSystemService(Context.POWER_SERVICE);
+ assertDelayedCondition("Unexpected screen interactive state",
+ () -> interactive == powerManager.isInteractive());
+ }
+
+ private void assertDelayedCondition(String errorMsg, ExpectedCondition condition) {
+ final long endTime = SystemClock.uptimeMillis() + GENERAL_TIMEOUT_MS;
+ while (SystemClock.uptimeMillis() <= endTime) {
+ if (condition.isTrue()) {
+ return;
+ }
+ SystemClock.sleep(GENERAL_INTERVAL_MS);
+ }
+ if (!condition.isTrue()) {
+ fail(errorMsg);
+ }
+ }
+
+ private void assertBatteryState(boolean pluggedIn) throws Exception {
+ final long endTime = SystemClock.uptimeMillis() + BATTERY_STATE_TIMEOUT_MS;
+ while (isDevicePluggedIn() != pluggedIn && SystemClock.uptimeMillis() <= endTime) {
+ Thread.sleep(BATTERY_STATE_CHECK_INTERVAL_MS);
+ }
+ if (isDevicePluggedIn() != pluggedIn) {
+ fail("Timed out waiting for the plugged-in state to change,"
+ + " expected pluggedIn: " + pluggedIn);
+ }
+ }
+
+ private boolean isDevicePluggedIn() {
+ final Intent batteryIntent = sContext.registerReceiver(null,
+ new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+ return batteryIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) > 0;
+ }
+
+ private String executeCmd(String cmd) throws Exception {
+ final String result = sUiDevice.executeShellCommand(cmd).trim();
+ Log.d(TAG, String.format("Result for '%s': %s", cmd, result));
+ return result;
+ }
+
+ private static String executeCmdSilent(String cmd) throws Exception {
+ return sUiDevice.executeShellCommand(cmd).trim();
+ }
+
+ private interface ExpectedCondition {
+ boolean isTrue();
+ }
+}
diff --git a/core/tests/featureflagtests/Android.mk b/core/tests/featureflagtests/Android.mk
index f2d2058..6330b8e 100644
--- a/core/tests/featureflagtests/Android.mk
+++ b/core/tests/featureflagtests/Android.mk
@@ -10,7 +10,7 @@
LOCAL_DX_FLAGS := --core-library
LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib android-support-test
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_PACKAGE_NAME := FrameworksCoreFeatureFlagTests
LOCAL_CERTIFICATE := platform
diff --git a/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java b/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java
index b8c4123..0b1b333 100644
--- a/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java
+++ b/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java
@@ -18,6 +18,7 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import android.content.Context;
@@ -59,7 +60,7 @@
@Test
public void testGetFlag_enabled_shouldReturnTrue() {
- SystemProperties.set(FeatureFlagUtils.FFLAG_PREFIX + TEST_FEATURE_NAME, "true");
+ FeatureFlagUtils.getAllFeatureFlags().put(TEST_FEATURE_NAME, "true");
assertTrue(FeatureFlagUtils.isEnabled(mContext, TEST_FEATURE_NAME));
}
@@ -96,7 +97,11 @@
@Test
public void testGetFlag_notSet_shouldReturnFalse() {
- assertFalse(FeatureFlagUtils.isEnabled(mContext, TEST_FEATURE_NAME));
+ assertFalse(FeatureFlagUtils.isEnabled(mContext, TEST_FEATURE_NAME + "does_not_exist"));
}
+ @Test
+ public void getAllFeatureFlags_shouldNotBeNull() {
+ assertNotNull(FeatureFlagUtils.getAllFeatureFlags());
+ }
}
diff --git a/core/tests/overlaytests/Android.mk b/core/tests/overlaytests/Android.mk
index bf69442..b798d87 100644
--- a/core/tests/overlaytests/Android.mk
+++ b/core/tests/overlaytests/Android.mk
@@ -1,4 +1,15 @@
-# Dummy makefile to halt recursive directory traversal.
+# 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.
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
+include $(call all-subdir-makefiles)
diff --git a/core/tests/overlaytests/OverlayAppFiltered/Android.mk b/core/tests/overlaytests/OverlayAppFiltered/Android.mk
index 8ba21df..f76de7a 100644
--- a/core/tests/overlaytests/OverlayAppFiltered/Android.mk
+++ b/core/tests/overlaytests/OverlayAppFiltered/Android.mk
@@ -3,8 +3,6 @@
LOCAL_MODULE_TAGS := tests
-LOCAL_JAVA_LIBRARIES += legacy-test
-
LOCAL_SDK_VERSION := system_current
LOCAL_PACKAGE_NAME := com.android.overlaytest.filtered_app_overlay
diff --git a/core/tests/overlaytests/OverlayAppFirst/Android.mk b/core/tests/overlaytests/OverlayAppFirst/Android.mk
index 51f4487..bf9416c 100644
--- a/core/tests/overlaytests/OverlayAppFirst/Android.mk
+++ b/core/tests/overlaytests/OverlayAppFirst/Android.mk
@@ -3,8 +3,6 @@
LOCAL_MODULE_TAGS := tests
-LOCAL_JAVA_LIBRARIES += legacy-test
-
LOCAL_SDK_VERSION := current
LOCAL_PACKAGE_NAME := com.android.overlaytest.first_app_overlay
diff --git a/core/tests/overlaytests/OverlayAppSecond/Android.mk b/core/tests/overlaytests/OverlayAppSecond/Android.mk
index b3cfd18..bb7d142 100644
--- a/core/tests/overlaytests/OverlayAppSecond/Android.mk
+++ b/core/tests/overlaytests/OverlayAppSecond/Android.mk
@@ -3,8 +3,6 @@
LOCAL_MODULE_TAGS := tests
-LOCAL_JAVA_LIBRARIES += legacy-test
-
LOCAL_SDK_VERSION := current
LOCAL_PACKAGE_NAME := com.android.overlaytest.second_app_overlay
diff --git a/core/tests/overlaytests/OverlayTest/Android.mk b/core/tests/overlaytests/OverlayTest/Android.mk
index 964348f..5fe7b91 100644
--- a/core/tests/overlaytests/OverlayTest/Android.mk
+++ b/core/tests/overlaytests/OverlayTest/Android.mk
@@ -7,7 +7,7 @@
LOCAL_DEX_PREOPT := false
-LOCAL_JAVA_LIBRARIES += legacy-test
+LOCAL_JAVA_LIBRARIES += android.test.base
LOCAL_MODULE_PATH := $(TARGET_OUT)/app
diff --git a/core/tests/overlaytests/OverlayTestOverlay/Android.mk b/core/tests/overlaytests/OverlayTestOverlay/Android.mk
index 5265d91..ed33046 100644
--- a/core/tests/overlaytests/OverlayTestOverlay/Android.mk
+++ b/core/tests/overlaytests/OverlayTestOverlay/Android.mk
@@ -3,8 +3,6 @@
LOCAL_MODULE_TAGS := tests
-LOCAL_JAVA_LIBRARIES += legacy-test
-
LOCAL_SDK_VERSION := current
LOCAL_PACKAGE_NAME := com.android.overlaytest.overlay
diff --git a/core/tests/systemproperties/Android.mk b/core/tests/systemproperties/Android.mk
index 4c2e224..57e2059 100644
--- a/core/tests/systemproperties/Android.mk
+++ b/core/tests/systemproperties/Android.mk
@@ -10,7 +10,7 @@
LOCAL_DX_FLAGS := --core-library
LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_PACKAGE_NAME := FrameworksCoreSystemPropertiesTests
LOCAL_CERTIFICATE := platform
diff --git a/core/tests/utillib/Android.mk b/core/tests/utillib/Android.mk
index 8811256..be1ab1f 100644
--- a/core/tests/utillib/Android.mk
+++ b/core/tests/utillib/Android.mk
@@ -19,7 +19,8 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_MODULE := frameworks-core-util-lib
-LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
+LOCAL_STATIC_JAVA_LIBRARIES := junit
+LOCAL_JAVA_LIBRARIES := android.test.base
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/core/tests/utiltests/Android.mk b/core/tests/utiltests/Android.mk
index 233d070..2dc1059 100644
--- a/core/tests/utiltests/Android.mk
+++ b/core/tests/utiltests/Android.mk
@@ -19,7 +19,7 @@
frameworks-base-testutils \
mockito-target-minus-junit4 \
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock
LOCAL_PACKAGE_NAME := FrameworksUtilTests
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 161a0c2..8e7147c 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -259,8 +259,9 @@
</privapp-permissions>
<privapp-permissions package="com.android.settings.intelligence">
- <permission name="android.permission.READ_SEARCH_INDEXABLES"/>
+ <permission name="android.permission.MANAGE_FINGERPRINT"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.permission.READ_SEARCH_INDEXABLES"/>
</privapp-permissions>
<privapp-permissions package="com.android.sharedstoragebackup">
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index b3bba07..74f8c71 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -404,6 +404,8 @@
# key 503 KEY_BRL_DOT7
# key 504 KEY_BRL_DOT8
+key 522 STAR
+key 523 POUND
key 580 APP_SWITCH
key 582 VOICE_ASSIST
diff --git a/data/keyboards/Generic_Iot.kl b/data/keyboards/Generic_Iot.kl
deleted file mode 100644
index 89df224..0000000
--- a/data/keyboards/Generic_Iot.kl
+++ /dev/null
@@ -1,443 +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.
-
-#
-# Generic key layout file for full alphabetic US English PC style external keyboards.
-#
-# This file is intentionally very generic and is intended to support a broad range of keyboards.
-# Do not edit the generic key layout to support a specific keyboard; instead, create
-# a new key layout file with the required keyboard configuration.
-#
-
-key 1 ESCAPE
-key 2 1
-key 3 2
-key 4 3
-key 5 4
-key 6 5
-key 7 6
-key 8 7
-key 9 8
-key 10 9
-key 11 0
-key 12 MINUS
-key 13 EQUALS
-key 14 DEL
-key 15 TAB
-key 16 Q
-key 17 W
-key 18 E
-key 19 R
-key 20 T
-key 21 Y
-key 22 U
-key 23 I
-key 24 O
-key 25 P
-key 26 LEFT_BRACKET
-key 27 RIGHT_BRACKET
-key 28 ENTER
-key 29 CTRL_LEFT
-key 30 A
-key 31 S
-key 32 D
-key 33 F
-key 34 G
-key 35 H
-key 36 J
-key 37 K
-key 38 L
-key 39 SEMICOLON
-key 40 APOSTROPHE
-key 41 GRAVE
-key 42 SHIFT_LEFT
-key 43 BACKSLASH
-key 44 Z
-key 45 X
-key 46 C
-key 47 V
-key 48 B
-key 49 N
-key 50 M
-key 51 COMMA
-key 52 PERIOD
-key 53 SLASH
-key 54 SHIFT_RIGHT
-key 55 NUMPAD_MULTIPLY
-key 56 ALT_LEFT
-key 57 SPACE
-key 58 CAPS_LOCK
-key 59 F1
-key 60 F2
-key 61 F3
-key 62 F4
-key 63 F5
-key 64 F6
-key 65 F7
-key 66 F8
-key 67 F9
-key 68 F10
-key 69 NUM_LOCK
-key 70 SCROLL_LOCK
-key 71 NUMPAD_7
-key 72 NUMPAD_8
-key 73 NUMPAD_9
-key 74 NUMPAD_SUBTRACT
-key 75 NUMPAD_4
-key 76 NUMPAD_5
-key 77 NUMPAD_6
-key 78 NUMPAD_ADD
-key 79 NUMPAD_1
-key 80 NUMPAD_2
-key 81 NUMPAD_3
-key 82 NUMPAD_0
-key 83 NUMPAD_DOT
-# key 84 (undefined)
-key 85 ZENKAKU_HANKAKU
-key 86 BACKSLASH
-key 87 F11
-key 88 F12
-key 89 RO
-# key 90 "KEY_KATAKANA"
-# key 91 "KEY_HIRAGANA"
-key 92 HENKAN
-key 93 KATAKANA_HIRAGANA
-key 94 MUHENKAN
-key 95 NUMPAD_COMMA
-key 96 NUMPAD_ENTER
-key 97 CTRL_RIGHT
-key 98 NUMPAD_DIVIDE
-key 99 SYSRQ
-key 100 ALT_RIGHT
-# key 101 "KEY_LINEFEED"
-key 102 MOVE_HOME
-key 103 DPAD_UP
-key 104 PAGE_UP
-key 105 DPAD_LEFT
-key 106 DPAD_RIGHT
-key 107 MOVE_END
-key 108 DPAD_DOWN
-key 109 PAGE_DOWN
-key 110 INSERT
-key 111 FORWARD_DEL
-# key 112 "KEY_MACRO"
-key 113 VOLUME_MUTE
-key 114 VOLUME_DOWN
-key 115 VOLUME_UP
-key 116 POWER
-key 117 NUMPAD_EQUALS
-# key 118 "KEY_KPPLUSMINUS"
-key 119 BREAK
-# key 120 (undefined)
-key 121 NUMPAD_COMMA
-key 122 KANA
-key 123 EISU
-key 124 YEN
-key 125 META_LEFT
-key 126 META_RIGHT
-key 127 MENU
-key 128 MEDIA_STOP
-# key 129 "KEY_AGAIN"
-# key 130 "KEY_PROPS"
-# key 131 "KEY_UNDO"
-# key 132 "KEY_FRONT"
-key 133 COPY
-# key 134 "KEY_OPEN"
-key 135 PASTE
-# key 136 "KEY_FIND"
-key 137 CUT
-# key 138 "KEY_HELP"
-key 139 MENU
-key 140 CALCULATOR
-# key 141 "KEY_SETUP"
-key 142 SLEEP
-key 143 WAKEUP
-# key 144 "KEY_FILE"
-# key 145 "KEY_SENDFILE"
-# key 146 "KEY_DELETEFILE"
-# key 147 "KEY_XFER"
-# key 148 "KEY_PROG1"
-# key 149 "KEY_PROG2"
-key 150 EXPLORER
-# key 151 "KEY_MSDOS"
-key 152 POWER
-# key 153 "KEY_DIRECTION"
-# key 154 "KEY_CYCLEWINDOWS"
-key 155 ENVELOPE
-key 156 BOOKMARK
-# key 157 "KEY_COMPUTER"
-key 158 BACK
-key 159 FORWARD
-key 160 MEDIA_CLOSE
-key 161 MEDIA_EJECT
-key 162 MEDIA_EJECT
-key 163 MEDIA_NEXT
-key 164 MEDIA_PLAY_PAUSE
-key 165 MEDIA_PREVIOUS
-key 166 MEDIA_STOP
-key 167 MEDIA_RECORD
-key 168 MEDIA_REWIND
-key 169 CALL
-# key 170 "KEY_ISO"
-key 171 MUSIC
-key 172 HOME
-# key 173 "KEY_REFRESH"
-# key 174 "KEY_EXIT"
-# key 175 "KEY_MOVE"
-# key 176 "KEY_EDIT"
-key 177 PAGE_UP
-key 178 PAGE_DOWN
-key 179 NUMPAD_LEFT_PAREN
-key 180 NUMPAD_RIGHT_PAREN
-# key 181 "KEY_NEW"
-# key 182 "KEY_REDO"
-# key 183 F13
-# key 184 F14
-# key 185 F15
-# key 186 F16
-# key 187 F17
-# key 188 F18
-# key 189 F19
-# key 190 F20
-# key 191 F21
-# key 192 F22
-# key 193 F23
-# key 194 F24
-# key 195 (undefined)
-# key 196 (undefined)
-# key 197 (undefined)
-# key 198 (undefined)
-# key 199 (undefined)
-key 200 MEDIA_PLAY
-key 201 MEDIA_PAUSE
-# key 202 "KEY_PROG3"
-# key 203 "KEY_PROG4"
-# key 204 (undefined)
-# key 205 "KEY_SUSPEND"
-# key 206 "KEY_CLOSE"
-key 207 MEDIA_PLAY
-key 208 MEDIA_FAST_FORWARD
-# key 209 "KEY_BASSBOOST"
-# key 210 "KEY_PRINT"
-# key 211 "KEY_HP"
-key 212 CAMERA
-key 213 MUSIC
-# key 214 "KEY_QUESTION"
-key 215 ENVELOPE
-# key 216 "KEY_CHAT"
-key 217 SEARCH
-# key 218 "KEY_CONNECT"
-# key 219 "KEY_FINANCE"
-# key 220 "KEY_SPORT"
-# key 221 "KEY_SHOP"
-# key 222 "KEY_ALTERASE"
-# key 223 "KEY_CANCEL"
-key 224 BRIGHTNESS_DOWN
-key 225 BRIGHTNESS_UP
-key 226 HEADSETHOOK
-key 227 POUND
-key 228 STAR
-
-key 256 BUTTON_1
-key 257 BUTTON_2
-key 258 BUTTON_3
-key 259 BUTTON_4
-key 260 BUTTON_5
-key 261 BUTTON_6
-key 262 BUTTON_7
-key 263 BUTTON_8
-key 264 BUTTON_9
-key 265 BUTTON_10
-key 266 BUTTON_11
-key 267 BUTTON_12
-key 268 BUTTON_13
-key 269 BUTTON_14
-key 270 BUTTON_15
-key 271 BUTTON_16
-
-key 288 BUTTON_1
-key 289 BUTTON_2
-key 290 BUTTON_3
-key 291 BUTTON_4
-key 292 BUTTON_5
-key 293 BUTTON_6
-key 294 BUTTON_7
-key 295 BUTTON_8
-key 296 BUTTON_9
-key 297 BUTTON_10
-key 298 BUTTON_11
-key 299 BUTTON_12
-key 300 BUTTON_13
-key 301 BUTTON_14
-key 302 BUTTON_15
-key 303 BUTTON_16
-
-
-key 304 BUTTON_A
-key 305 BUTTON_B
-key 306 BUTTON_C
-key 307 BUTTON_X
-key 308 BUTTON_Y
-key 309 BUTTON_Z
-key 310 BUTTON_L1
-key 311 BUTTON_R1
-key 312 BUTTON_L2
-key 313 BUTTON_R2
-key 314 BUTTON_SELECT
-key 315 BUTTON_START
-key 316 BUTTON_MODE
-key 317 BUTTON_THUMBL
-key 318 BUTTON_THUMBR
-
-
-# key 352 "KEY_OK"
-key 353 DPAD_CENTER
-# key 354 "KEY_GOTO"
-# key 355 "KEY_CLEAR"
-# key 356 "KEY_POWER2"
-# key 357 "KEY_OPTION"
-# key 358 "KEY_INFO"
-# key 359 "KEY_TIME"
-# key 360 "KEY_VENDOR"
-# key 361 "KEY_ARCHIVE"
-key 362 GUIDE
-# key 363 "KEY_CHANNEL"
-# key 364 "KEY_FAVORITES"
-# key 365 "KEY_EPG"
-key 366 DVR
-# key 367 "KEY_MHP"
-# key 368 "KEY_LANGUAGE"
-# key 369 "KEY_TITLE"
-# key 370 "KEY_SUBTITLE"
-# key 371 "KEY_ANGLE"
-# key 372 "KEY_ZOOM"
-# key 373 "KEY_MODE"
-# key 374 "KEY_KEYBOARD"
-# key 375 "KEY_SCREEN"
-# key 376 "KEY_PC"
-key 377 TV
-# key 378 "KEY_TV2"
-# key 379 "KEY_VCR"
-# key 380 "KEY_VCR2"
-# key 381 "KEY_SAT"
-# key 382 "KEY_SAT2"
-# key 383 "KEY_CD"
-# key 384 "KEY_TAPE"
-# key 385 "KEY_RADIO"
-# key 386 "KEY_TUNER"
-# key 387 "KEY_PLAYER"
-# key 388 "KEY_TEXT"
-# key 389 "KEY_DVD"
-# key 390 "KEY_AUX"
-# key 391 "KEY_MP3"
-# key 392 "KEY_AUDIO"
-# key 393 "KEY_VIDEO"
-# key 394 "KEY_DIRECTORY"
-# key 395 "KEY_LIST"
-# key 396 "KEY_MEMO"
-key 397 CALENDAR
-# key 398 "KEY_RED"
-# key 399 "KEY_GREEN"
-# key 400 "KEY_YELLOW"
-# key 401 "KEY_BLUE"
-key 402 CHANNEL_UP
-key 403 CHANNEL_DOWN
-# key 404 "KEY_FIRST"
-# key 405 "KEY_LAST"
-# key 406 "KEY_AB"
-# key 407 "KEY_NEXT"
-# key 408 "KEY_RESTART"
-# key 409 "KEY_SLOW"
-# key 410 "KEY_SHUFFLE"
-# key 411 "KEY_BREAK"
-# key 412 "KEY_PREVIOUS"
-# key 413 "KEY_DIGITS"
-# key 414 "KEY_TEEN"
-# key 415 "KEY_TWEN"
-
-key 429 CONTACTS
-
-# key 448 "KEY_DEL_EOL"
-# key 449 "KEY_DEL_EOS"
-# key 450 "KEY_INS_LINE"
-# key 451 "KEY_DEL_LINE"
-
-
-key 464 FUNCTION
-key 465 ESCAPE FUNCTION
-key 466 F1 FUNCTION
-key 467 F2 FUNCTION
-key 468 F3 FUNCTION
-key 469 F4 FUNCTION
-key 470 F5 FUNCTION
-key 471 F6 FUNCTION
-key 472 F7 FUNCTION
-key 473 F8 FUNCTION
-key 474 F9 FUNCTION
-key 475 F10 FUNCTION
-key 476 F11 FUNCTION
-key 477 F12 FUNCTION
-key 478 1 FUNCTION
-key 479 2 FUNCTION
-key 480 D FUNCTION
-key 481 E FUNCTION
-key 482 F FUNCTION
-key 483 S FUNCTION
-key 484 B FUNCTION
-
-
-# key 497 KEY_BRL_DOT1
-# key 498 KEY_BRL_DOT2
-# key 499 KEY_BRL_DOT3
-# key 500 KEY_BRL_DOT4
-# key 501 KEY_BRL_DOT5
-# key 502 KEY_BRL_DOT6
-# key 503 KEY_BRL_DOT7
-# key 504 KEY_BRL_DOT8
-
-key 580 APP_SWITCH
-key 582 VOICE_ASSIST
-
-# Keys defined by HID usages
-key usage 0x0c006F BRIGHTNESS_UP
-key usage 0x0c0070 BRIGHTNESS_DOWN
-
-# Joystick and game controller axes.
-# Axes that are not mapped will be assigned generic axis numbers by the input subsystem.
-axis 0x00 X
-axis 0x01 Y
-axis 0x02 Z
-axis 0x03 RX
-axis 0x04 RY
-axis 0x05 RZ
-axis 0x06 THROTTLE
-axis 0x07 RUDDER
-axis 0x08 WHEEL
-axis 0x09 GAS
-axis 0x0a BRAKE
-axis 0x10 HAT_X
-axis 0x11 HAT_Y
-
-# LEDs
-led 0x00 NUM_LOCK
-led 0x01 CAPS_LOCK
-led 0x02 SCROLL_LOCK
-led 0x03 COMPOSE
-led 0x04 KANA
-led 0x05 SLEEP
-led 0x06 SUSPEND
-led 0x07 MUTE
-led 0x08 MISC
-led 0x09 MAIL
-led 0x0a CHARGING
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 7b2e21a..c71585f 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -896,6 +896,13 @@
return mVectorState.getNativeRenderer();
}
+ /**
+ * @hide
+ */
+ public void setAntiAlias(boolean aa) {
+ nSetAntiAlias(mVectorState.mNativeTree.get(), aa);
+ }
+
static class VectorDrawableState extends ConstantState {
// Variables below need to be copied (deep copy if applicable) for mutation.
int[] mThemeAttrs;
@@ -2269,6 +2276,8 @@
@FastNative
private static native float nGetRootAlpha(long rendererPtr);
@FastNative
+ private static native void nSetAntiAlias(long rendererPtr, boolean aa);
+ @FastNative
private static native void nSetAllowCaching(long rendererPtr, boolean allowCaching);
@FastNative
diff --git a/keystore/java/android/security/AttestedKeyPair.java b/keystore/java/android/security/AttestedKeyPair.java
new file mode 100644
index 0000000..c6bff5c
--- /dev/null
+++ b/keystore/java/android/security/AttestedKeyPair.java
@@ -0,0 +1,75 @@
+/*
+ * 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 android.security;
+
+import java.security.KeyPair;
+import java.security.cert.Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * The {@code AttestedKeyPair} class contains a {@code KeyPair} instance of
+ * keys generated by Keystore and owned by KeyChain, as well as an attestation
+ * record for the key.
+ *
+ * <p>Such keys can be obtained by calling
+ * {@link android.app.admin.DevicePolicyManager#generateKeyPair}.
+ */
+
+public final class AttestedKeyPair {
+ private final KeyPair mKeyPair;
+ private final Certificate[] mAttestationRecord;
+
+ /**
+ * @hide Only created by the platform, no need to expose as public API.
+ */
+ public AttestedKeyPair(KeyPair keyPair, Certificate[] attestationRecord) {
+ mKeyPair = keyPair;
+ mAttestationRecord = attestationRecord;
+ }
+
+ /**
+ * Returns the generated key pair associated with the attestation record
+ * in this instance.
+ */
+ public KeyPair getKeyPair() {
+ return mKeyPair;
+ }
+
+ /**
+ * Returns the attestation record for the key pair in this instance.
+ *
+ * The attestation record is a chain of certificates. The leaf certificate links to the public
+ * key of this key pair and other properties of the key or the device. If the key is in secure
+ * hardware, and if the secure hardware supports attestation, the leaf certificate will be
+ * signed by a chain of certificates rooted at a trustworthy CA key. Otherwise the chain will be
+ * rooted at an untrusted certificate.
+ *
+ * The attestation record could be for properties of the key, or include device identifiers.
+ *
+ * See {@link android.security.keystore.KeyGenParameterSpec.Builder#setAttestationChallenge}
+ * and <a href="https://developer.android.com/training/articles/security-key-attestation.html">
+ * Key Attestation</a> for the format of the attestation record inside the certificate.
+ */
+ public List<Certificate> getAttestationRecord() {
+ if (mAttestationRecord == null) {
+ return new ArrayList();
+ }
+ return Arrays.asList(mAttestationRecord);
+ }
+}
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index 635432d..b4331b2 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -16,6 +16,7 @@
package android.security;
import android.content.pm.StringParceledListSlice;
+import android.security.keystore.ParcelableKeyGenParameterSpec;
/**
* Caller is required to ensure that {@link KeyStore#unlock
@@ -31,6 +32,8 @@
boolean isUserSelectable(String alias);
void setUserSelectable(String alias, boolean isUserSelectable);
+ boolean generateKeyPair(in String algorithm, in ParcelableKeyGenParameterSpec spec);
+
// APIs used by CertInstaller and DevicePolicyManager
String installCaCertificate(in byte[] caCertificate);
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 3fe730f..2daf733 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -40,6 +40,7 @@
import java.io.ByteArrayInputStream;
import java.io.Closeable;
+import java.security.KeyPair;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
@@ -418,6 +419,18 @@
@Nullable @WorkerThread
public static PrivateKey getPrivateKey(@NonNull Context context, @NonNull String alias)
throws KeyChainException, InterruptedException {
+ KeyPair keyPair = getKeyPair(context, alias);
+ if (keyPair != null) {
+ return keyPair.getPrivate();
+ }
+
+ return null;
+ }
+
+ /** @hide */
+ @Nullable @WorkerThread
+ public static KeyPair getKeyPair(@NonNull Context context, @NonNull String alias)
+ throws KeyChainException, InterruptedException {
if (alias == null) {
throw new NullPointerException("alias == null");
}
@@ -439,7 +452,7 @@
return null;
} else {
try {
- return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
+ return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
KeyStore.getInstance(), keyId, KeyStore.UID_SELF);
} catch (RuntimeException | UnrecoverableKeyException e) {
throw new KeyChainException(e);
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index ed40b77..87677d4 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -195,7 +195,7 @@
* <pre> {@code
* KeyGenerator keyGenerator = KeyGenerator.getInstance(
* KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
- * keyGenerator.initialize(
+ * keyGenerator.init(
* new KeyGenParameterSpec.Builder("key2",
* KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
* .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
@@ -219,7 +219,7 @@
* <pre> {@code
* KeyGenerator keyGenerator = KeyGenerator.getInstance(
* KeyProperties.KEY_ALGORITHM_HMAC_SHA256, "AndroidKeyStore");
- * keyGenerator.initialize(
+ * keyGenerator.init(
* new KeyGenParameterSpec.Builder("key2", KeyProperties.PURPOSE_SIGN).build());
* SecretKey key = keyGenerator.generateKey();
* Mac mac = Mac.getInstance("HmacSHA256");
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.aidl
similarity index 71%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.aidl
index 4ccdea5..3fb7b4f 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,11 +14,6 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+package android.security.keystore;
-import android.telephony.SubscriptionInfo;
-
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
-}
-
+parcelable ParcelableKeyGenParameterSpec;
diff --git a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
new file mode 100644
index 0000000..b15e0a2
--- /dev/null
+++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
@@ -0,0 +1,170 @@
+/*
+ * 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 android.security.keystore;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.RSAKeyGenParameterSpec;
+import java.util.Date;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * A parcelable version of KeyGenParameterSpec
+ * @hide only used for communicating with the DPMS.
+ */
+public final class ParcelableKeyGenParameterSpec implements Parcelable {
+ private static final int ALGORITHM_PARAMETER_SPEC_NONE = 1;
+ private static final int ALGORITHM_PARAMETER_SPEC_RSA = 2;
+ private static final int ALGORITHM_PARAMETER_SPEC_EC = 3;
+
+ private final KeyGenParameterSpec mSpec;
+
+ public ParcelableKeyGenParameterSpec(
+ KeyGenParameterSpec spec) {
+ mSpec = spec;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ private static void writeOptionalDate(Parcel out, Date date) {
+ if (date != null) {
+ out.writeBoolean(true);
+ out.writeLong(date.getTime());
+ } else {
+ out.writeBoolean(false);
+ }
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mSpec.getKeystoreAlias());
+ out.writeInt(mSpec.getPurposes());
+ out.writeInt(mSpec.getUid());
+ out.writeInt(mSpec.getKeySize());
+
+ // Only needs to support RSAKeyGenParameterSpec and ECGenParameterSpec.
+ AlgorithmParameterSpec algoSpec = mSpec.getAlgorithmParameterSpec();
+ if (algoSpec == null) {
+ out.writeInt(ALGORITHM_PARAMETER_SPEC_NONE);
+ } else if (algoSpec instanceof RSAKeyGenParameterSpec) {
+ RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) algoSpec;
+ out.writeInt(ALGORITHM_PARAMETER_SPEC_RSA);
+ out.writeInt(rsaSpec.getKeysize());
+ out.writeByteArray(rsaSpec.getPublicExponent().toByteArray());
+ } else if (algoSpec instanceof ECGenParameterSpec) {
+ ECGenParameterSpec ecSpec = (ECGenParameterSpec) algoSpec;
+ out.writeInt(ALGORITHM_PARAMETER_SPEC_EC);
+ out.writeString(ecSpec.getName());
+ } else {
+ throw new IllegalArgumentException(
+ String.format("Unknown algorithm parameter spec: %s", algoSpec.getClass()));
+ }
+ out.writeByteArray(mSpec.getCertificateSubject().getEncoded());
+ out.writeByteArray(mSpec.getCertificateSerialNumber().toByteArray());
+ writeOptionalDate(out, mSpec.getCertificateNotBefore());
+ writeOptionalDate(out, mSpec.getCertificateNotAfter());
+ writeOptionalDate(out, mSpec.getKeyValidityStart());
+ writeOptionalDate(out, mSpec.getKeyValidityForOriginationEnd());
+ writeOptionalDate(out, mSpec.getKeyValidityForConsumptionEnd());
+ out.writeStringArray(mSpec.getDigests());
+ out.writeStringArray(mSpec.getEncryptionPaddings());
+ out.writeStringArray(mSpec.getSignaturePaddings());
+ out.writeStringArray(mSpec.getBlockModes());
+ out.writeBoolean(mSpec.isRandomizedEncryptionRequired());
+ out.writeBoolean(mSpec.isUserAuthenticationRequired());
+ out.writeInt(mSpec.getUserAuthenticationValidityDurationSeconds());
+ out.writeByteArray(mSpec.getAttestationChallenge());
+ out.writeBoolean(mSpec.isUniqueIdIncluded());
+ out.writeBoolean(mSpec.isUserAuthenticationValidWhileOnBody());
+ out.writeBoolean(mSpec.isInvalidatedByBiometricEnrollment());
+ }
+
+ private static Date readDateOrNull(Parcel in) {
+ boolean hasDate = in.readBoolean();
+ if (hasDate) {
+ return new Date(in.readLong());
+ } else {
+ return null;
+ }
+ }
+
+ private ParcelableKeyGenParameterSpec(Parcel in) {
+ String keystoreAlias = in.readString();
+ int purposes = in.readInt();
+ KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keystoreAlias, purposes);
+ builder.setUid(in.readInt());
+ builder.setKeySize(in.readInt());
+
+ int keySpecType = in.readInt();
+ AlgorithmParameterSpec algorithmSpec = null;
+ if (keySpecType == ALGORITHM_PARAMETER_SPEC_NONE) {
+ algorithmSpec = null;
+ } else if (keySpecType == ALGORITHM_PARAMETER_SPEC_RSA) {
+ int rsaKeySize = in.readInt();
+ BigInteger publicExponent = new BigInteger(in.createByteArray());
+ algorithmSpec = new RSAKeyGenParameterSpec(rsaKeySize, publicExponent);
+ } else if (keySpecType == ALGORITHM_PARAMETER_SPEC_EC) {
+ String stdName = in.readString();
+ algorithmSpec = new ECGenParameterSpec(stdName);
+ } else {
+ throw new IllegalArgumentException(
+ String.format("Unknown algorithm parameter spec: %d", algorithmSpec));
+ }
+ builder.setAlgorithmParameterSpec(algorithmSpec);
+ builder.setCertificateSubject(new X500Principal(in.createByteArray()));
+ builder.setCertificateSerialNumber(new BigInteger(in.createByteArray()));
+ builder.setCertificateNotBefore(readDateOrNull(in));
+ builder.setCertificateNotAfter(readDateOrNull(in));
+ builder.setKeyValidityStart(readDateOrNull(in));
+ builder.setKeyValidityForOriginationEnd(readDateOrNull(in));
+ builder.setKeyValidityForConsumptionEnd(readDateOrNull(in));
+ builder.setDigests(in.createStringArray());
+ builder.setEncryptionPaddings(in.createStringArray());
+ builder.setSignaturePaddings(in.createStringArray());
+ builder.setBlockModes(in.createStringArray());
+ builder.setRandomizedEncryptionRequired(in.readBoolean());
+ builder.setUserAuthenticationRequired(in.readBoolean());
+ builder.setUserAuthenticationValidityDurationSeconds(in.readInt());
+ builder.setAttestationChallenge(in.createByteArray());
+ builder.setUniqueIdIncluded(in.readBoolean());
+ builder.setUserAuthenticationValidWhileOnBody(in.readBoolean());
+ builder.setInvalidatedByBiometricEnrollment(in.readBoolean());
+ mSpec = builder.build();
+ }
+
+ public static final Creator<ParcelableKeyGenParameterSpec> CREATOR = new Creator<ParcelableKeyGenParameterSpec>() {
+ @Override
+ public ParcelableKeyGenParameterSpec createFromParcel(Parcel in) {
+ return new ParcelableKeyGenParameterSpec(in);
+ }
+
+ @Override
+ public ParcelableKeyGenParameterSpec[] newArray(int size) {
+ return new ParcelableKeyGenParameterSpec[size];
+ }
+ };
+
+ public KeyGenParameterSpec getSpec() {
+ return mSpec;
+ }
+}
diff --git a/keystore/tests/Android.mk b/keystore/tests/Android.mk
new file mode 100644
index 0000000..51adde4
--- /dev/null
+++ b/keystore/tests/Android.mk
@@ -0,0 +1,34 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+# LOCAL_MODULE := keystore
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-test \
+ legacy-android-test
+
+LOCAL_PACKAGE_NAME := KeystoreTests
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
diff --git a/keystore/tests/AndroidManifest.xml b/keystore/tests/AndroidManifest.xml
new file mode 100644
index 0000000..9bf2d0c
--- /dev/null
+++ b/keystore/tests/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.tests">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.tests"
+ android:label="Tests for Keystore">
+ </instrumentation>
+</manifest>
+
diff --git a/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java
new file mode 100644
index 0000000..73b489f
--- /dev/null
+++ b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java
@@ -0,0 +1,180 @@
+/*
+ * 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 android.security;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import android.os.Parcel;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.ParcelableKeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.support.test.runner.AndroidJUnit4;
+import java.math.BigInteger;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.RSAKeyGenParameterSpec;
+import java.util.Date;
+import javax.security.auth.x500.X500Principal;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit tests for {@link ParcelableKeyGenParameterSpec}. */
+@RunWith(AndroidJUnit4.class)
+public final class ParcelableKeyGenParameterSpecTest {
+ static final String ALIAS = "keystore-alias";
+ static final String ANOTHER_ALIAS = "another-keystore-alias";
+ static final int KEY_PURPOSES = KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY;
+ static final int UID = 1230;
+ static final int KEYSIZE = 2048;
+ static final X500Principal SUBJECT = new X500Principal("CN=subject");
+ static final BigInteger SERIAL = new BigInteger("1234567890");
+ static final Date NOT_BEFORE = new Date(1511799590);
+ static final Date NOT_AFTER = new Date(1511899590);
+ static final Date KEY_VALIDITY_START = new Date(1511799591);
+ static final Date KEY_VALIDITY_FOR_ORIG_END = new Date(1511799593);
+ static final Date KEY_VALIDITY_FOR_CONSUMPTION_END = new Date(1511799594);
+ static final String DIGEST = KeyProperties.DIGEST_SHA256;
+ static final String ENCRYPTION_PADDING = KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1;
+ static final String SIGNATURE_PADDING = KeyProperties.SIGNATURE_PADDING_RSA_PSS;
+ static final String BLOCK_MODE = KeyProperties.BLOCK_MODE_CBC;
+ static final int USER_AUTHENTICATION_DURATION = 300;
+ static final byte[] ATTESTATION_CHALLENGE = new byte[] {'c', 'h'};
+
+ KeyGenParameterSpec configureDefaultSpec() {
+ return new KeyGenParameterSpec.Builder(ALIAS, KEY_PURPOSES)
+ .setUid(UID)
+ .setKeySize(KEYSIZE)
+ .setCertificateSubject(SUBJECT)
+ .setCertificateSerialNumber(SERIAL)
+ .setCertificateNotBefore(NOT_BEFORE)
+ .setCertificateNotAfter(NOT_AFTER)
+ .setKeyValidityStart(KEY_VALIDITY_START)
+ .setKeyValidityForOriginationEnd(KEY_VALIDITY_FOR_ORIG_END)
+ .setKeyValidityForConsumptionEnd(KEY_VALIDITY_FOR_CONSUMPTION_END)
+ .setDigests(DIGEST)
+ .setEncryptionPaddings(ENCRYPTION_PADDING)
+ .setSignaturePaddings(SIGNATURE_PADDING)
+ .setBlockModes(BLOCK_MODE)
+ .setRandomizedEncryptionRequired(true)
+ .setUserAuthenticationRequired(true)
+ .setUserAuthenticationValidityDurationSeconds(USER_AUTHENTICATION_DURATION)
+ .setAttestationChallenge(ATTESTATION_CHALLENGE)
+ .setUniqueIdIncluded(true)
+ .setUserAuthenticationValidWhileOnBody(true)
+ .setInvalidatedByBiometricEnrollment(true)
+ .build();
+ }
+
+ void validateSpecValues(KeyGenParameterSpec spec, int uid, String alias) {
+ assertThat(spec.getKeystoreAlias(), is(alias));
+ assertThat(spec.getPurposes(), is(KEY_PURPOSES));
+ assertThat(spec.getUid(), is(uid));
+ assertThat(spec.getKeySize(), is(KEYSIZE));
+ assertThat(spec.getCertificateSubject(), is(SUBJECT));
+ assertThat(spec.getCertificateSerialNumber(), is(SERIAL));
+ assertThat(spec.getCertificateNotBefore(), is(NOT_BEFORE));
+ assertThat(spec.getCertificateNotAfter(), is(NOT_AFTER));
+ assertThat(spec.getKeyValidityStart(), is(KEY_VALIDITY_START));
+ assertThat(spec.getKeyValidityForOriginationEnd(), is(KEY_VALIDITY_FOR_ORIG_END));
+ assertThat(spec.getKeyValidityForConsumptionEnd(), is(KEY_VALIDITY_FOR_CONSUMPTION_END));
+ assertThat(spec.getDigests(), is(new String[] {DIGEST}));
+ assertThat(spec.getEncryptionPaddings(), is(new String[] {ENCRYPTION_PADDING}));
+ assertThat(spec.getSignaturePaddings(), is(new String[] {SIGNATURE_PADDING}));
+ assertThat(spec.getBlockModes(), is(new String[] {BLOCK_MODE}));
+ assertThat(spec.isRandomizedEncryptionRequired(), is(true));
+ assertThat(spec.isUserAuthenticationRequired(), is(true));
+ assertThat(
+ spec.getUserAuthenticationValidityDurationSeconds(),
+ is(USER_AUTHENTICATION_DURATION));
+ assertThat(spec.getAttestationChallenge(), is(ATTESTATION_CHALLENGE));
+ assertThat(spec.isUniqueIdIncluded(), is(true));
+ assertThat(spec.isUserAuthenticationValidWhileOnBody(), is(true));
+ assertThat(spec.isInvalidatedByBiometricEnrollment(), is(true));
+ }
+
+ private Parcel parcelForReading(ParcelableKeyGenParameterSpec spec) {
+ Parcel parcel = Parcel.obtain();
+ spec.writeToParcel(parcel, spec.describeContents());
+
+ parcel.setDataPosition(0);
+ return parcel;
+ }
+
+ @Test
+ public void testParcelingWithAllValues() {
+ ParcelableKeyGenParameterSpec spec =
+ new ParcelableKeyGenParameterSpec(configureDefaultSpec());
+ Parcel parcel = parcelForReading(spec);
+ ParcelableKeyGenParameterSpec fromParcel =
+ ParcelableKeyGenParameterSpec.CREATOR.createFromParcel(parcel);
+ validateSpecValues(fromParcel.getSpec(), UID, ALIAS);
+ assertThat(parcel.dataAvail(), is(0));
+ }
+
+ @Test
+ public void testParcelingWithNullValues() {
+ ParcelableKeyGenParameterSpec spec = new ParcelableKeyGenParameterSpec(
+ new KeyGenParameterSpec.Builder(ALIAS, KEY_PURPOSES).build());
+
+ Parcel parcel = parcelForReading(spec);
+ KeyGenParameterSpec fromParcel = ParcelableKeyGenParameterSpec.CREATOR
+ .createFromParcel(parcel)
+ .getSpec();
+ assertThat(fromParcel.getKeystoreAlias(), is(ALIAS));
+ assertThat(fromParcel.getPurposes(), is(KEY_PURPOSES));
+ assertThat(fromParcel.getCertificateNotBefore(), is(new Date(0L)));
+ assertThat(fromParcel.getCertificateNotAfter(), is(new Date(2461449600000L)));
+ assertThat(parcel.dataAvail(), is(0));
+ }
+
+ @Test
+ public void testParcelingRSAAlgoParameter() {
+ RSAKeyGenParameterSpec rsaSpec =
+ new RSAKeyGenParameterSpec(2048, new BigInteger("5231123"));
+ ParcelableKeyGenParameterSpec spec = new ParcelableKeyGenParameterSpec(
+ new KeyGenParameterSpec.Builder(ALIAS, KEY_PURPOSES)
+ .setAlgorithmParameterSpec(rsaSpec)
+ .build());
+
+ Parcel parcel = parcelForReading(spec);
+ KeyGenParameterSpec fromParcel =
+ ParcelableKeyGenParameterSpec.CREATOR.createFromParcel(parcel).getSpec();
+ RSAKeyGenParameterSpec parcelSpec =
+ (RSAKeyGenParameterSpec) fromParcel.getAlgorithmParameterSpec();
+ // Compare individual fields as RSAKeyGenParameterSpec, on android, does not
+ // implement equals()
+ assertEquals(parcelSpec.getKeysize(), rsaSpec.getKeysize());
+ assertEquals(parcelSpec.getPublicExponent(), rsaSpec.getPublicExponent());
+ }
+
+ @Test
+ public void testParcelingECAlgoParameter() {
+ ECGenParameterSpec ecSpec = new ECGenParameterSpec("P-256");
+ ParcelableKeyGenParameterSpec spec = new ParcelableKeyGenParameterSpec(
+ new KeyGenParameterSpec.Builder(ALIAS, KEY_PURPOSES)
+ .setAlgorithmParameterSpec(ecSpec)
+ .build());
+ Parcel parcel = parcelForReading(spec);
+ KeyGenParameterSpec fromParcel =
+ ParcelableKeyGenParameterSpec.CREATOR.createFromParcel(parcel).getSpec();
+ // Compare individual fields as ECGenParameterSpec, on android, does not
+ // implement equals()
+ ECGenParameterSpec parcelSpec = (ECGenParameterSpec) fromParcel.getAlgorithmParameterSpec();
+ assertEquals(parcelSpec.getName(), ecSpec.getName());
+ }
+}
diff --git a/legacy-test/Android.mk b/legacy-test/Android.mk
deleted file mode 100644
index 4c150c8..0000000
--- a/legacy-test/Android.mk
+++ /dev/null
@@ -1,169 +0,0 @@
-#
-# Copyright (C) 2016 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-# Build the legacy-test library
-# =============================
-# This contains the junit.framework and android.test classes that were in
-# Android API level 25 excluding those from android.test.runner.
-# Also contains the com.android.internal.util.Predicate[s] classes.
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE := legacy-test
-LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
-
-include $(BUILD_JAVA_LIBRARY)
-
-# Build the repackaged-legacy-test library
-# ========================================
-# This contains repackaged versions of the classes from legacy-test.
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE := repackaged-legacy-test
-LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
-LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# Generate the stub source files for legacy.test.stubs
-# ====================================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := \
- core-oj \
- core-libart \
- framework \
-
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/src
-
-LEGACY_TEST_OUTPUT_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/legacy.test.stubs_intermediates/api.txt
-LEGACY_TEST_OUTPUT_REMOVED_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/legacy.test.stubs_intermediates/removed.txt
-
-LEGACY_TEST_API_FILE := $(LOCAL_PATH)/api/legacy-test-current.txt
-LEGACY_TEST_REMOVED_API_FILE := $(LOCAL_PATH)/api/legacy-test-removed.txt
-
-LOCAL_DROIDDOC_OPTIONS:= \
- -stubpackages android.test:android.test.suitebuilder.annotation:com.android.internal.util:junit.framework \
- -stubsourceonly \
- -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/legacy.test.stubs_intermediates/src \
- -nodocs \
- -api $(LEGACY_TEST_OUTPUT_API_FILE) \
- -removedApi $(LEGACY_TEST_OUTPUT_REMOVED_API_FILE) \
-
-LOCAL_UNINSTALLABLE_MODULE := true
-LOCAL_MODULE := legacy-test-api-stubs-gen
-
-include $(BUILD_DROIDDOC)
-
-# Remember the target that will trigger the code generation.
-legacy_test_api_gen_stamp := $(full_target)
-
-# Add some additional dependencies
-$(LEGACY_TEST_OUTPUT_API_FILE): $(full_target)
-$(LEGACY_TEST_OUTPUT_REMOVED_API_FILE): $(full_target)
-
-# Build the legacy.test.stubs library
-# ===================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := legacy.test.stubs
-
-LOCAL_SOURCE_FILES_ALL_GENERATED := true
-LOCAL_SDK_VERSION := current
-LOCAL_ADDITIONAL_DEPENDENCIES := $(legacy_test_api_gen_stamp)
-
-# Make sure to run droiddoc first to generate the stub source files.
-LOCAL_ADDITIONAL_DEPENDENCIES := $(legacy_test_api_gen_stamp)
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# Archive a copy of the classes.jar in SDK build.
-$(call dist-for-goals,sdk win_sdk,$(full_classes_jar):legacy.test.stubs.jar)
-
-# Check that the legacy.test.stubs library has not changed
-# ========================================================
-
-# Check that the API we're building hasn't changed from the not-yet-released
-# SDK version.
-$(eval $(call check-api, \
- check-legacy-test-api-current, \
- $(LEGACY_TEST_API_FILE), \
- $(LEGACY_TEST_OUTPUT_API_FILE), \
- $(LEGACY_TEST_REMOVED_API_FILE), \
- $(LEGACY_TEST_OUTPUT_REMOVED_API_FILE), \
- -error 2 -error 3 -error 4 -error 5 -error 6 \
- -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
- -error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 \
- -error 25 -error 26 -error 27, \
- cat $(LOCAL_PATH)/api/apicheck_msg_legacy_test.txt, \
- check-legacy-test-api, \
- $(call doc-timestamp-for,legacy-test-api-stubs-gen) \
- ))
-
-.PHONY: check-legacy-test-api
-checkapi: check-legacy-test-api
-
-.PHONY: update-legacy-test-api
-update-api: update-legacy-test-api
-
-update-legacy-test-api: $(LEGACY_TEST_OUTPUT_API_FILE) | $(ACP)
- @echo Copying current.txt
- $(hide) $(ACP) $(LEGACY_TEST_OUTPUT_API_FILE) $(LEGACY_TEST_API_FILE)
- @echo Copying removed.txt
- $(hide) $(ACP) $(LEGACY_TEST_OUTPUT_REMOVED_API_FILE) $(LEGACY_TEST_REMOVED_API_FILE)
-
-# Build the legacy-android-test library
-# =====================================
-# This contains the android.test classes that were in Android API level 25,
-# including those from android.test.runner.
-# Also contains the com.android.internal.util.Predicate[s] classes.
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src/android) \
- $(call all-java-files-under, ../test-runner/src/android) \
- $(call all-java-files-under, ../test-mock/src/android) \
- $(call all-java-files-under, src/com)
-LOCAL_MODULE := legacy-android-test
-LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework junit
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-ifeq ($(HOST_OS),linux)
-# Build the legacy-performance-test-hostdex library
-# =================================================
-# This contains the android.test.PerformanceTestCase class only
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := src/android/test/PerformanceTestCase.java
-LOCAL_MODULE := legacy-performance-test-hostdex
-
-include $(BUILD_HOST_DALVIK_STATIC_JAVA_LIBRARY)
-endif # HOST_OS == linux
-
-legacy_test_api_gen_stamp :=
diff --git a/legacy-test/api/apicheck_msg_legacy_test.txt b/legacy-test/api/apicheck_msg_legacy_test.txt
deleted file mode 100644
index ad5f235..0000000
--- a/legacy-test/api/apicheck_msg_legacy_test.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-
-******************************
-You have tried to change the API from what has been previously approved.
-
-To make these errors go away, you have two choices:
- 1) You can add "@hide" javadoc comments to the methods, etc. listed in the
- errors above.
-
- 2) You can update legacy-test-current.txt by executing the following command:
- make update-legacy-test-api
-
- To submit the revised legacy-test-current.txt to the main Android repository,
- you will need approval.
-******************************
-
-
-
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index 158df13..da0205d 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -47,12 +47,12 @@
}
std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path, bool system) {
- return ApkAssets::LoadImpl(path, nullptr, nullptr, system, false /*load_as_shared_library*/);
+ return LoadImpl({} /*fd*/, path, nullptr, nullptr, system, false /*load_as_shared_library*/);
}
std::unique_ptr<const ApkAssets> ApkAssets::LoadAsSharedLibrary(const std::string& path,
bool system) {
- return ApkAssets::LoadImpl(path, nullptr, nullptr, system, true /*load_as_shared_library*/);
+ return LoadImpl({} /*fd*/, path, nullptr, nullptr, system, true /*load_as_shared_library*/);
}
std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path,
@@ -70,8 +70,15 @@
LOG(ERROR) << "failed to load IDMAP " << idmap_path;
return {};
}
- return LoadImpl(loaded_idmap->OverlayApkPath(), std::move(idmap_asset), std::move(loaded_idmap),
- system, false /*load_as_shared_library*/);
+ return LoadImpl({} /*fd*/, loaded_idmap->OverlayApkPath(), std::move(idmap_asset),
+ std::move(loaded_idmap), system, false /*load_as_shared_library*/);
+}
+
+std::unique_ptr<const ApkAssets> ApkAssets::LoadFromFd(unique_fd fd,
+ const std::string& friendly_name,
+ bool system, bool force_shared_lib) {
+ return LoadImpl(std::move(fd), friendly_name, nullptr /*idmap_asset*/, nullptr /*loaded_idmap*/,
+ system, force_shared_lib);
}
std::unique_ptr<Asset> ApkAssets::CreateAssetFromFile(const std::string& path) {
@@ -96,11 +103,19 @@
}
std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(
- const std::string& path, std::unique_ptr<Asset> idmap_asset,
+ unique_fd fd, const std::string& path, std::unique_ptr<Asset> idmap_asset,
std::unique_ptr<const LoadedIdmap> loaded_idmap, bool system, bool load_as_shared_library) {
ATRACE_CALL();
+
::ZipArchiveHandle unmanaged_handle;
- int32_t result = ::OpenArchive(path.c_str(), &unmanaged_handle);
+ int32_t result;
+ if (fd >= 0) {
+ result =
+ ::OpenArchiveFd(fd.release(), path.c_str(), &unmanaged_handle, true /*assume_ownership*/);
+ } else {
+ result = ::OpenArchive(path.c_str(), &unmanaged_handle);
+ }
+
if (result != 0) {
LOG(ERROR) << "Failed to open APK '" << path << "' " << ::ErrorCodeString(result);
return {};
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 83c82af..415d3e3 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -299,10 +299,9 @@
const PackageGroup& package_group = package_groups_[idx];
const size_t package_count = package_group.packages_.size();
+ FindEntryResult current_entry;
for (size_t i = 0; i < package_count; i++) {
const LoadedPackage* loaded_package = package_group.packages_[i];
-
- FindEntryResult current_entry;
if (!loaded_package->FindEntry(type_idx, entry_id, *desired_config, ¤t_entry)) {
continue;
}
@@ -394,7 +393,7 @@
return kInvalidCookie;
}
- if (dtohl(entry.entry->flags) & ResTable_entry::FLAG_COMPLEX) {
+ if (dtohs(entry.entry->flags) & ResTable_entry::FLAG_COMPLEX) {
if (!may_be_bag) {
LOG(ERROR) << base::StringPrintf("Resource %08x is a complex map type.", resid);
return kInvalidCookie;
@@ -427,7 +426,6 @@
ATRACE_CALL();
constexpr const int kMaxIterations = 20;
- *out_last_reference = 0u;
for (size_t iteration = 0u; in_out_value->dataType == Res_value::TYPE_REFERENCE &&
in_out_value->data != 0u && iteration < kMaxIterations;
iteration++) {
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index c361ea2..28548e2 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -18,6 +18,7 @@
#include "androidfw/LoadedArsc.h"
+#include <algorithm>
#include <cstddef>
#include <limits>
@@ -128,9 +129,14 @@
// Precondition: The header passed in has already been verified, so reading any fields and trusting
// the ResChunk_header is safe.
static bool VerifyResTableType(const ResTable_type* header) {
+ if (header->id == 0) {
+ LOG(ERROR) << "RES_TABLE_TYPE_TYPE has invalid ID 0.";
+ return false;
+ }
+
const size_t entry_count = dtohl(header->entryCount);
if (entry_count > std::numeric_limits<uint16_t>::max()) {
- LOG(ERROR) << "Too many entries in RES_TABLE_TYPE_TYPE.";
+ LOG(ERROR) << "RES_TABLE_TYPE_TYPE has too many entries (" << entry_count << ").";
return false;
}
@@ -140,17 +146,17 @@
const size_t offsets_length = sizeof(uint32_t) * entry_count;
if (offsets_offset > entries_offset || entries_offset - offsets_offset < offsets_length) {
- LOG(ERROR) << "Entry offsets overlap actual entry data.";
+ LOG(ERROR) << "RES_TABLE_TYPE_TYPE entry offsets overlap actual entry data.";
return false;
}
if (entries_offset > dtohl(header->header.size)) {
- LOG(ERROR) << "Entry offsets extend beyond chunk.";
+ LOG(ERROR) << "RES_TABLE_TYPE_TYPE entry offsets extend beyond chunk.";
return false;
}
if (entries_offset & 0x03) {
- LOG(ERROR) << "Entries start at unaligned address.";
+ LOG(ERROR) << "RES_TABLE_TYPE_TYPE entries start at unaligned address.";
return false;
}
return true;
@@ -235,7 +241,6 @@
return true;
}
-template <bool Verified>
bool LoadedPackage::FindEntry(const TypeSpecPtr& type_spec_ptr, uint16_t entry_idx,
const ResTable_config& config, FindEntryResult* out_entry) const {
const ResTable_config* best_config = nullptr;
@@ -244,31 +249,56 @@
for (uint32_t i = 0; i < type_spec_ptr->type_count; i++) {
const Type* type = &type_spec_ptr->types[i];
+ const ResTable_type* type_chunk = type->type;
if (type->configuration.match(config) &&
(best_config == nullptr || type->configuration.isBetterThan(*best_config, &config))) {
// The configuration matches and is better than the previous selection.
// Find the entry value if it exists for this configuration.
- const size_t entry_count = dtohl(type->type->entryCount);
- const size_t offsets_offset = dtohs(type->type->header.headerSize);
- if (entry_idx < entry_count) {
- // If the package hasn't been verified, do bounds checking.
- if (!Verified) {
- if (!VerifyResTableType(type->type)) {
- continue;
- }
+ const size_t entry_count = dtohl(type_chunk->entryCount);
+ const size_t offsets_offset = dtohs(type_chunk->header.headerSize);
+
+ // Check if there is the desired entry in this type.
+
+ if (type_chunk->flags & ResTable_type::FLAG_SPARSE) {
+ // This is encoded as a sparse map, so perform a binary search.
+ const ResTable_sparseTypeEntry* sparse_indices =
+ reinterpret_cast<const ResTable_sparseTypeEntry*>(
+ reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
+ const ResTable_sparseTypeEntry* sparse_indices_end = sparse_indices + entry_count;
+ const ResTable_sparseTypeEntry* result =
+ std::lower_bound(sparse_indices, sparse_indices_end, entry_idx,
+ [](const ResTable_sparseTypeEntry& entry, uint16_t entry_idx) {
+ return dtohs(entry.idx) < entry_idx;
+ });
+
+ if (result == sparse_indices_end || dtohs(result->idx) != entry_idx) {
+ // No entry found.
+ continue;
+ }
+
+ // Extract the offset from the entry. Each offset must be a multiple of 4 so we store it as
+ // the real offset divided by 4.
+ best_offset = uint32_t{dtohs(result->offset)} * 4u;
+ } else {
+ if (entry_idx >= entry_count) {
+ // This entry cannot be here.
+ continue;
}
const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
- reinterpret_cast<const uint8_t*>(type->type) + offsets_offset);
+ reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
const uint32_t offset = dtohl(entry_offsets[entry_idx]);
- if (offset != ResTable_type::NO_ENTRY) {
- // There is an entry for this resource, record it.
- best_config = &type->configuration;
- best_type = type->type;
- best_offset = offset;
+ if (offset == ResTable_type::NO_ENTRY) {
+ continue;
}
+
+ // There is an entry for this resource, record it.
+ best_offset = offset;
}
+
+ best_config = &type->configuration;
+ best_type = type_chunk;
}
}
@@ -276,10 +306,8 @@
return false;
}
- if (!Verified) {
- if (!VerifyResTableEntry(best_type, best_offset, entry_idx)) {
- return false;
- }
+ if (UNLIKELY(!VerifyResTableEntry(best_type, best_offset, entry_idx))) {
+ return false;
}
const ResTable_entry* best_entry = reinterpret_cast<const ResTable_entry*>(
@@ -301,7 +329,7 @@
// If the type IDs are offset in this package, we need to take that into account when searching
// for a type.
const TypeSpecPtr& ptr = type_specs_[type_idx - type_id_offset_];
- if (ptr == nullptr) {
+ if (UNLIKELY(ptr == nullptr)) {
return false;
}
@@ -312,41 +340,7 @@
return false;
}
}
-
- // Don't bother checking if the entry ID is larger than the number of entries.
- if (entry_idx >= dtohl(ptr->type_spec->entryCount)) {
- return false;
- }
-
- if (verified_) {
- return FindEntry<true>(ptr, entry_idx, config, out_entry);
- }
- return FindEntry<false>(ptr, entry_idx, config, out_entry);
-}
-
-static bool VerifyType(const Chunk& chunk) {
- ATRACE_CALL();
- const ResTable_type* header = chunk.header<ResTable_type, kResTableTypeMinSize>();
-
- if (!VerifyResTableType(header)) {
- return false;
- }
-
- const size_t entry_count = dtohl(header->entryCount);
- const size_t offsets_offset = chunk.header_size();
-
- // Check each entry offset.
- const uint32_t* offsets =
- reinterpret_cast<const uint32_t*>(reinterpret_cast<const uint8_t*>(header) + offsets_offset);
- for (size_t i = 0; i < entry_count; i++) {
- uint32_t offset = dtohl(offsets[i]);
- if (offset != ResTable_type::NO_ENTRY) {
- if (!VerifyResTableEntry(header, offset, i)) {
- return false;
- }
- }
- }
- return true;
+ return FindEntry(ptr, entry_idx, config, out_entry);
}
void LoadedPackage::CollectConfigurations(bool exclude_mipmap,
@@ -461,7 +455,7 @@
sizeof(ResTable_package) - sizeof(ResTable_package::typeIdOffset);
const ResTable_package* header = chunk.header<ResTable_package, kMinPackageSize>();
if (header == nullptr) {
- LOG(ERROR) << "Chunk RES_TABLE_PACKAGE_TYPE is too small.";
+ LOG(ERROR) << "RES_TABLE_PACKAGE_TYPE too small.";
return {};
}
@@ -483,7 +477,7 @@
if (header->header.headerSize >= sizeof(ResTable_package)) {
uint32_t type_id_offset = dtohl(header->typeIdOffset);
if (type_id_offset > std::numeric_limits<uint8_t>::max()) {
- LOG(ERROR) << "Type ID offset in RES_TABLE_PACKAGE_TYPE is too large.";
+ LOG(ERROR) << "RES_TABLE_PACKAGE_TYPE type ID offset too large.";
return {};
}
loaded_package->type_id_offset_ = static_cast<int>(type_id_offset);
@@ -514,7 +508,7 @@
status_t err = loaded_package->type_string_pool_.setTo(
child_chunk.header<ResStringPool_header>(), child_chunk.size());
if (err != NO_ERROR) {
- LOG(ERROR) << "Corrupt package type string pool.";
+ LOG(ERROR) << "RES_STRING_POOL_TYPE for types corrupt.";
return {};
}
} else if (pool_address == header_address + dtohl(header->keyStrings)) {
@@ -522,11 +516,11 @@
status_t err = loaded_package->key_string_pool_.setTo(
child_chunk.header<ResStringPool_header>(), child_chunk.size());
if (err != NO_ERROR) {
- LOG(ERROR) << "Corrupt package key string pool.";
+ LOG(ERROR) << "RES_STRING_POOL_TYPE for keys corrupt.";
return {};
}
} else {
- LOG(WARNING) << "Too many string pool chunks found in package.";
+ LOG(WARNING) << "Too many RES_STRING_POOL_TYPEs found in RES_TABLE_PACKAGE_TYPE.";
}
} break;
@@ -557,18 +551,18 @@
const ResTable_typeSpec* type_spec = child_chunk.header<ResTable_typeSpec>();
if (type_spec == nullptr) {
- LOG(ERROR) << "Chunk RES_TABLE_TYPE_SPEC_TYPE is too small.";
+ LOG(ERROR) << "RES_TABLE_TYPE_SPEC_TYPE too small.";
return {};
}
if (type_spec->id == 0) {
- LOG(ERROR) << "Chunk RES_TABLE_TYPE_SPEC_TYPE has invalid ID 0.";
+ LOG(ERROR) << "RES_TABLE_TYPE_SPEC_TYPE has invalid ID 0.";
return {};
}
if (loaded_package->type_id_offset_ + static_cast<int>(type_spec->id) >
std::numeric_limits<uint8_t>::max()) {
- LOG(ERROR) << "Chunk RES_TABLE_TYPE_SPEC_TYPE has out of range ID.";
+ LOG(ERROR) << "RES_TABLE_TYPE_SPEC_TYPE has out of range ID.";
return {};
}
@@ -580,12 +574,12 @@
// There can only be 2^16 entries in a type, because that is the ID
// space for entries (EEEE) in the resource ID 0xPPTTEEEE.
if (entry_count > std::numeric_limits<uint16_t>::max()) {
- LOG(ERROR) << "Too many entries in RES_TABLE_TYPE_SPEC_TYPE: " << entry_count << ".";
+ LOG(ERROR) << "RES_TABLE_TYPE_SPEC_TYPE has too many entries (" << entry_count << ").";
return {};
}
if (entry_count * sizeof(uint32_t) > chunk.data_size()) {
- LOG(ERROR) << "Chunk too small to hold entries in RES_TABLE_TYPE_SPEC_TYPE.";
+ LOG(ERROR) << "RES_TABLE_TYPE_SPEC_TYPE too small to hold entries.";
return {};
}
@@ -604,41 +598,32 @@
case RES_TABLE_TYPE_TYPE: {
const ResTable_type* type = child_chunk.header<ResTable_type, kResTableTypeMinSize>();
if (type == nullptr) {
- LOG(ERROR) << "Chunk RES_TABLE_TYPE_TYPE is too small.";
+ LOG(ERROR) << "RES_TABLE_TYPE_TYPE too small.";
return {};
}
- if (type->id == 0) {
- LOG(ERROR) << "Chunk RES_TABLE_TYPE_TYPE has invalid ID 0.";
+ if (!VerifyResTableType(type)) {
return {};
}
// Type chunks must be preceded by their TypeSpec chunks.
if (!types_builder || type->id - 1 != last_type_idx) {
- LOG(ERROR) << "Found RES_TABLE_TYPE_TYPE chunk without RES_TABLE_TYPE_SPEC_TYPE.";
+ LOG(ERROR) << "RES_TABLE_TYPE_TYPE found without preceding RES_TABLE_TYPE_SPEC_TYPE.";
return {};
}
- // Only verify the type if we haven't already failed verification.
- if (loaded_package->verified_) {
- if (!VerifyType(child_chunk)) {
- LOG(WARNING) << "Package failed verification, resource retrieval may be slower";
- loaded_package->verified_ = false;
- }
- }
-
types_builder->AddType(type);
} break;
case RES_TABLE_LIBRARY_TYPE: {
const ResTable_lib_header* lib = child_chunk.header<ResTable_lib_header>();
if (lib == nullptr) {
- LOG(ERROR) << "Chunk RES_TABLE_LIBRARY_TYPE is too small.";
+ LOG(ERROR) << "RES_TABLE_LIBRARY_TYPE too small.";
return {};
}
if (child_chunk.data_size() / sizeof(ResTable_lib_entry) < dtohl(lib->count)) {
- LOG(ERROR) << "Chunk too small to hold entries in RES_TABLE_LIBRARY_TYPE.";
+ LOG(ERROR) << "RES_TABLE_LIBRARY_TYPE too small to hold entries.";
return {};
}
@@ -705,7 +690,7 @@
const uint8_t type_id = get_type_id(resid);
const uint16_t entry_id = get_entry_id(resid);
- if (type_id == 0) {
+ if (UNLIKELY(type_id == 0)) {
LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid);
return false;
}
@@ -723,7 +708,7 @@
ATRACE_CALL();
const ResTable_header* header = chunk.header<ResTable_header>();
if (header == nullptr) {
- LOG(ERROR) << "Chunk RES_TABLE_TYPE is too small.";
+ LOG(ERROR) << "RES_TABLE_TYPE too small.";
return false;
}
@@ -742,11 +727,11 @@
status_t err = global_string_pool_.setTo(child_chunk.header<ResStringPool_header>(),
child_chunk.size());
if (err != NO_ERROR) {
- LOG(ERROR) << "Corrupt string pool.";
+ LOG(ERROR) << "RES_STRING_POOL_TYPE corrupt.";
return false;
}
} else {
- LOG(WARNING) << "Multiple string pool chunks found in resource table.";
+ LOG(WARNING) << "Multiple RES_STRING_POOL_TYPEs found in RES_TABLE_TYPE.";
}
break;
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index 3a307fc..69702e3 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -21,6 +21,7 @@
#include <string>
#include "android-base/macros.h"
+#include "android-base/unique_fd.h"
#include "androidfw/Asset.h"
#include "androidfw/LoadedArsc.h"
@@ -51,6 +52,16 @@
static std::unique_ptr<const ApkAssets> LoadOverlay(const std::string& idmap_path,
bool system = false);
+ // Creates an ApkAssets from the given file descriptor, and takes ownership of the file
+ // descriptor. The `friendly_name` is some name that will be used to identify the source of
+ // this ApkAssets in log messages and other debug scenarios.
+ // If `system` is true, the package is marked as a system package, and allows some functions to
+ // filter out this package when computing what configurations/resources are available.
+ // If `force_shared_lib` is true, any package with ID 0x7f is loaded as a shared library.
+ static std::unique_ptr<const ApkAssets> LoadFromFd(base::unique_fd fd,
+ const std::string& friendly_name, bool system,
+ bool force_shared_lib);
+
std::unique_ptr<Asset> Open(const std::string& path,
Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM) const;
@@ -69,7 +80,7 @@
private:
DISALLOW_COPY_AND_ASSIGN(ApkAssets);
- static std::unique_ptr<const ApkAssets> LoadImpl(const std::string& path,
+ static std::unique_ptr<const ApkAssets> LoadImpl(base::unique_fd fd, const std::string& path,
std::unique_ptr<Asset> idmap_asset,
std::unique_ptr<const LoadedIdmap> loaded_idmap,
bool system, bool load_as_shared_library);
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index a77c4b9..b033137 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -210,7 +210,7 @@
// are OR'd together with `in_out_flags`.
// `in_out_config` is populated with the configuration for which the resolved value was defined.
// `out_last_reference` is populated with the last reference ID before resolving to an actual
- // value.
+ // value. This is only initialized if the passed in `in_out_value` is a reference.
// Returns the cookie of the APK the resolved resource was defined in, or kInvalidCookie if
// it was not found.
ApkAssetsCookie ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value,
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 377735b..965e2db 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -119,11 +119,6 @@
return overlay_;
}
- // Returns true if this package is verified to be valid.
- inline bool IsVerified() const {
- return verified_;
- }
-
// Returns the map of package name to package ID used in this LoadedPackage. At runtime, a
// package could have been assigned a different package ID than what this LoadedPackage was
// compiled with. AssetManager rewrites the package IDs so that they are compatible at runtime.
@@ -145,7 +140,6 @@
LoadedPackage();
- template <bool Verified>
bool FindEntry(const util::unique_cptr<TypeSpec>& type_spec_ptr, uint16_t entry_idx,
const ResTable_config& config, FindEntryResult* out_entry) const;
@@ -157,7 +151,6 @@
bool dynamic_ = false;
bool system_ = false;
bool overlay_ = false;
- bool verified_ = true;
ByteBucketArray<util::unique_cptr<TypeSpec>> type_specs_;
std::vector<DynamicPackageEntry> dynamic_package_map_;
diff --git a/libs/androidfw/tests/ApkAssets_test.cpp b/libs/androidfw/tests/ApkAssets_test.cpp
index d65d93f..6c43a67 100644
--- a/libs/androidfw/tests/ApkAssets_test.cpp
+++ b/libs/androidfw/tests/ApkAssets_test.cpp
@@ -24,6 +24,7 @@
#include "TestHelpers.h"
#include "data/basic/R.h"
+using ::android::base::unique_fd;
using ::com::android::basic::R;
namespace android {
@@ -38,7 +39,25 @@
const LoadedPackage* loaded_package = loaded_arsc->GetPackageForId(0x7f010000);
ASSERT_NE(nullptr, loaded_package);
- EXPECT_TRUE(loaded_package->IsVerified());
+
+ std::unique_ptr<Asset> asset = loaded_apk->Open("res/layout/main.xml");
+ ASSERT_NE(nullptr, asset);
+}
+
+TEST(ApkAssetsTest, LoadApkFromFd) {
+ const std::string path = GetTestDataPath() + "/basic/basic.apk";
+ unique_fd fd(::open(path.c_str(), O_RDONLY | O_BINARY));
+ ASSERT_GE(fd.get(), 0);
+
+ std::unique_ptr<const ApkAssets> loaded_apk =
+ ApkAssets::LoadFromFd(std::move(fd), path, false /*system*/, false /*force_shared_lib*/);
+ ASSERT_NE(nullptr, loaded_apk);
+
+ const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
+ ASSERT_NE(nullptr, loaded_arsc);
+
+ const LoadedPackage* loaded_package = loaded_arsc->GetPackageForId(0x7f010000);
+ ASSERT_NE(nullptr, loaded_package);
std::unique_ptr<Asset> asset = loaded_apk->Open("res/layout/main.xml");
ASSERT_NE(nullptr, asset);
@@ -93,20 +112,6 @@
ASSERT_NE(nullptr, loaded_overlay_apk);
}
-TEST(ApkAssetsTest, LoadUnverifiableApk) {
- std::unique_ptr<const ApkAssets> loaded_apk =
- ApkAssets::Load(GetTestDataPath() + "/unverified/unverified.apk");
- ASSERT_NE(nullptr, loaded_apk);
-
- const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
- ASSERT_NE(nullptr, loaded_arsc);
-
- const LoadedPackage* loaded_package = loaded_arsc->GetPackageForId(0x7f010000);
- ASSERT_NE(nullptr, loaded_package);
-
- EXPECT_FALSE(loaded_package->IsVerified());
-}
-
TEST(ApkAssetsTest, CreateAndDestroyAssetKeepsApkAssetsOpen) {
std::unique_ptr<const ApkAssets> loaded_apk =
ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
@@ -132,7 +137,7 @@
ASSERT_NE(nullptr, asset);
off64_t start, length;
- base::unique_fd fd(asset->openFileDescriptor(&start, &length));
+ unique_fd fd(asset->openFileDescriptor(&start, &length));
EXPECT_GE(fd.get(), 0);
lseek64(fd.get(), start, SEEK_SET);
diff --git a/libs/androidfw/tests/AssetManager2_bench.cpp b/libs/androidfw/tests/AssetManager2_bench.cpp
index 739e733..85e8f25 100644
--- a/libs/androidfw/tests/AssetManager2_bench.cpp
+++ b/libs/androidfw/tests/AssetManager2_bench.cpp
@@ -26,12 +26,10 @@
#include "data/basic/R.h"
#include "data/libclient/R.h"
#include "data/styles/R.h"
-#include "data/unverified/R.h"
namespace app = com::android::app;
namespace basic = com::android::basic;
namespace libclient = com::android::libclient;
-namespace unverified = com::android::unverified;
namespace android {
@@ -83,37 +81,6 @@
}
BENCHMARK(BM_AssetManagerLoadFrameworkAssetsOld);
-static void GetResourceBenchmark(const std::vector<std::string>& paths,
- const ResTable_config* config, uint32_t resid,
- benchmark::State& state) {
- std::vector<std::unique_ptr<const ApkAssets>> apk_assets;
- std::vector<const ApkAssets*> apk_assets_ptrs;
- for (const std::string& path : paths) {
- std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path);
- if (apk == nullptr) {
- state.SkipWithError(base::StringPrintf("Failed to load assets %s", path.c_str()).c_str());
- return;
- }
- apk_assets_ptrs.push_back(apk.get());
- apk_assets.push_back(std::move(apk));
- }
-
- AssetManager2 assetmanager;
- assetmanager.SetApkAssets(apk_assets_ptrs);
- if (config != nullptr) {
- assetmanager.SetConfiguration(*config);
- }
-
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
-
- while (state.KeepRunning()) {
- assetmanager.GetResource(resid, false /* may_be_bag */, 0u /* density_override */, &value,
- &selected_config, &flags);
- }
-}
-
static void BM_AssetManagerGetResource(benchmark::State& state) {
GetResourceBenchmark({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/,
basic::R::integer::number1, state);
@@ -126,12 +93,6 @@
}
BENCHMARK(BM_AssetManagerGetResourceOld);
-static void BM_AssetManagerGetResourceUnverified(benchmark::State& state) {
- GetResourceBenchmark({GetTestDataPath() + "/unverified/unverified.apk"}, nullptr /*config*/,
- unverified::R::integer::number1, state);
-}
-BENCHMARK(BM_AssetManagerGetResourceUnverified);
-
static void BM_AssetManagerGetLibraryResource(benchmark::State& state) {
GetResourceBenchmark(
{GetTestDataPath() + "/lib_two/lib_two.apk", GetTestDataPath() + "/lib_one/lib_one.apk",
@@ -214,30 +175,6 @@
}
BENCHMARK(BM_AssetManagerGetBagOld);
-static void BM_AssetManagerGetBagUnverified(benchmark::State& state) {
- std::unique_ptr<const ApkAssets> apk =
- ApkAssets::Load(GetTestDataPath() + "/unverified/unverified.apk");
- if (apk == nullptr) {
- state.SkipWithError("Failed to load assets");
- return;
- }
-
- AssetManager2 assets;
- assets.SetApkAssets({apk.get()});
-
- while (state.KeepRunning()) {
- const ResolvedBag* bag = assets.GetBag(unverified::R::array::integerArray1);
- const auto bag_end = end(bag);
- for (auto iter = begin(bag); iter != bag_end; ++iter) {
- uint32_t key = iter->key;
- Res_value value = iter->value;
- benchmark::DoNotOptimize(key);
- benchmark::DoNotOptimize(value);
- }
- }
-}
-BENCHMARK(BM_AssetManagerGetBagUnverified);
-
static void BM_AssetManagerGetResourceLocales(benchmark::State& state) {
std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
if (apk == nullptr) {
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index ab1a22e..92462a6 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -28,7 +28,6 @@
#include "data/libclient/R.h"
#include "data/styles/R.h"
#include "data/system/R.h"
-#include "data/unverified/R.h"
namespace app = com::android::app;
namespace appaslib = com::android::appaslib::app;
@@ -36,7 +35,6 @@
namespace lib_one = com::android::lib_one;
namespace lib_two = com::android::lib_two;
namespace libclient = com::android::libclient;
-namespace unverified = com::android::unverified;
namespace android {
@@ -319,7 +317,7 @@
EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
EXPECT_EQ(basic::R::integer::ref2, value.data);
- uint32_t last_ref;
+ uint32_t last_ref = 0u;
cookie = assetmanager.ResolveReference(cookie, &value, &selected_config, &flags, &last_ref);
ASSERT_NE(kInvalidCookie, cookie);
EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
@@ -342,7 +340,7 @@
EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
EXPECT_EQ(basic::R::array::integerArray1, value.data);
- uint32_t last_ref;
+ uint32_t last_ref = 0u;
cookie = assetmanager.ResolveReference(cookie, &value, &selected_config, &flags, &last_ref);
ASSERT_NE(kInvalidCookie, cookie);
EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
@@ -350,6 +348,25 @@
EXPECT_EQ(basic::R::array::integerArray1, last_ref);
}
+TEST_F(AssetManager2Test, KeepLastReferenceIdUnmodifiedIfNoReferenceIsResolved) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({basic_assets_.get()});
+
+ ResTable_config selected_config;
+ memset(&selected_config, 0, sizeof(selected_config));
+
+ uint32_t flags = 0u;
+
+ // Create some kind of Res_value that is NOT a reference.
+ Res_value value;
+ value.dataType = Res_value::TYPE_STRING;
+ value.data = 0;
+
+ uint32_t last_ref = basic::R::string::test1;
+ EXPECT_EQ(1, assetmanager.ResolveReference(1, &value, &selected_config, &flags, &last_ref));
+ EXPECT_EQ(basic::R::string::test1, last_ref);
+}
+
static bool IsConfigurationPresent(const std::set<ResTable_config>& configurations,
const ResTable_config& configuration) {
return configurations.count(configuration) > 0;
@@ -433,30 +450,4 @@
TEST_F(AssetManager2Test, OpensFileFromMultipleApkAssets) {}
-TEST_F(AssetManager2Test, OperateOnUnverifiedApkAssets) {
- std::unique_ptr<const ApkAssets> unverified_assets =
- ApkAssets::Load(GetTestDataPath() + "/unverified/unverified.apk");
- ASSERT_NE(nullptr, unverified_assets);
-
- AssetManager2 assetmanager;
- assetmanager.SetApkAssets({unverified_assets.get()});
-
- Res_value value;
- ResTable_config config;
- uint32_t flags;
-
- EXPECT_EQ(kInvalidCookie,
- assetmanager.GetResource(unverified::R::string::test1, false /*may_be_bag*/, 0u, &value,
- &config, &flags));
- EXPECT_EQ(kInvalidCookie,
- assetmanager.GetResource(unverified::R::string::test2, false /*may_be_bag*/, 0u, &value,
- &config, &flags));
- EXPECT_NE(kInvalidCookie,
- assetmanager.GetResource(unverified::R::integer::number1, false /*may_be_bag*/, 0u,
- &value, &config, &flags));
-
- EXPECT_EQ(nullptr, assetmanager.GetBag(unverified::R::style::Theme1));
- EXPECT_NE(nullptr, assetmanager.GetBag(unverified::R::array::integerArray1));
-}
-
} // namespace android
diff --git a/libs/androidfw/tests/BenchmarkHelpers.cpp b/libs/androidfw/tests/BenchmarkHelpers.cpp
index 3619b7e..7149bee 100644
--- a/libs/androidfw/tests/BenchmarkHelpers.cpp
+++ b/libs/androidfw/tests/BenchmarkHelpers.cpp
@@ -18,6 +18,7 @@
#include "android-base/stringprintf.h"
#include "androidfw/AssetManager.h"
+#include "androidfw/AssetManager2.h"
namespace android {
@@ -48,4 +49,34 @@
}
}
+void GetResourceBenchmark(const std::vector<std::string>& paths, const ResTable_config* config,
+ uint32_t resid, benchmark::State& state) {
+ std::vector<std::unique_ptr<const ApkAssets>> apk_assets;
+ std::vector<const ApkAssets*> apk_assets_ptrs;
+ for (const std::string& path : paths) {
+ std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path);
+ if (apk == nullptr) {
+ state.SkipWithError(base::StringPrintf("Failed to load assets %s", path.c_str()).c_str());
+ return;
+ }
+ apk_assets_ptrs.push_back(apk.get());
+ apk_assets.push_back(std::move(apk));
+ }
+
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets(apk_assets_ptrs);
+ if (config != nullptr) {
+ assetmanager.SetConfiguration(*config);
+ }
+
+ Res_value value;
+ ResTable_config selected_config;
+ uint32_t flags;
+
+ while (state.KeepRunning()) {
+ assetmanager.GetResource(resid, false /* may_be_bag */, 0u /* density_override */, &value,
+ &selected_config, &flags);
+ }
+}
+
} // namespace android
diff --git a/libs/androidfw/tests/BenchmarkHelpers.h b/libs/androidfw/tests/BenchmarkHelpers.h
index 0bb96b5..eb0939d 100644
--- a/libs/androidfw/tests/BenchmarkHelpers.h
+++ b/libs/androidfw/tests/BenchmarkHelpers.h
@@ -30,6 +30,9 @@
void GetResourceBenchmarkOld(const std::vector<std::string>& paths, const ResTable_config* config,
uint32_t resid, ::benchmark::State& state);
+void GetResourceBenchmark(const std::vector<std::string>& paths, const ResTable_config* config,
+ uint32_t resid, benchmark::State& state);
+
} // namespace android
#endif // ANDROIDFW_TESTS_BENCHMARKHELPERS_H
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index 954a54d..37ddafb 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -19,11 +19,13 @@
#include "TestHelpers.h"
#include "data/basic/R.h"
#include "data/libclient/R.h"
+#include "data/sparse/R.h"
#include "data/styles/R.h"
namespace app = com::android::app;
namespace basic = com::android::basic;
namespace libclient = com::android::libclient;
+namespace sparse = com::android::sparse;
namespace android {
@@ -68,6 +70,23 @@
ASSERT_NE(nullptr, entry.entry);
}
+TEST(LoadedArscTest, LoadSparseEntryApp) {
+ std::string contents;
+ ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/sparse/sparse.apk", "resources.arsc",
+ &contents));
+
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ ASSERT_NE(nullptr, loaded_arsc);
+
+ ResTable_config config;
+ memset(&config, 0, sizeof(config));
+ config.sdkVersion = 26;
+
+ FindEntryResult entry;
+ ASSERT_TRUE(loaded_arsc->FindEntry(sparse::R::integer::foo_9, config, &entry));
+ ASSERT_NE(nullptr, entry.entry);
+}
+
TEST(LoadedArscTest, LoadSharedLibrary) {
std::string contents;
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/lib_one/lib_one.apk", "resources.arsc",
diff --git a/libs/androidfw/tests/SparseEntry_bench.cpp b/libs/androidfw/tests/SparseEntry_bench.cpp
index d6dc07d..c9b4ad8 100644
--- a/libs/androidfw/tests/SparseEntry_bench.cpp
+++ b/libs/androidfw/tests/SparseEntry_bench.cpp
@@ -24,40 +24,40 @@
namespace android {
-static void BM_SparseEntryGetResourceSparseSmall(benchmark::State& state) {
+static void BM_SparseEntryGetResourceOldSparse(benchmark::State& state, uint32_t resid) {
ResTable_config config;
memset(&config, 0, sizeof(config));
config.sdkVersion = 26;
- GetResourceBenchmarkOld({GetTestDataPath() + "/sparse/sparse.apk"}, &config,
- sparse::R::integer::foo_9, state);
+ GetResourceBenchmarkOld({GetTestDataPath() + "/sparse/sparse.apk"}, &config, resid, state);
}
-BENCHMARK(BM_SparseEntryGetResourceSparseSmall);
+BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldSparse, Small, sparse::R::integer::foo_9);
+BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldSparse, Large, sparse::R::string::foo_999);
-static void BM_SparseEntryGetResourceNotSparseSmall(benchmark::State& state) {
+static void BM_SparseEntryGetResourceOldNotSparse(benchmark::State& state, uint32_t resid) {
ResTable_config config;
memset(&config, 0, sizeof(config));
config.sdkVersion = 26;
- GetResourceBenchmarkOld({GetTestDataPath() + "/sparse/not_sparse.apk"}, &config,
- sparse::R::integer::foo_9, state);
+ GetResourceBenchmarkOld({GetTestDataPath() + "/sparse/not_sparse.apk"}, &config, resid, state);
}
-BENCHMARK(BM_SparseEntryGetResourceNotSparseSmall);
+BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldNotSparse, Small, sparse::R::integer::foo_9);
+BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldNotSparse, Large, sparse::R::string::foo_999);
-static void BM_SparseEntryGetResourceSparseLarge(benchmark::State& state) {
+static void BM_SparseEntryGetResourceSparse(benchmark::State& state, uint32_t resid) {
ResTable_config config;
memset(&config, 0, sizeof(config));
config.sdkVersion = 26;
- GetResourceBenchmarkOld({GetTestDataPath() + "/sparse/sparse.apk"}, &config,
- sparse::R::string::foo_999, state);
+ GetResourceBenchmark({GetTestDataPath() + "/sparse/sparse.apk"}, &config, resid, state);
}
-BENCHMARK(BM_SparseEntryGetResourceSparseLarge);
+BENCHMARK_CAPTURE(BM_SparseEntryGetResourceSparse, Small, sparse::R::integer::foo_9);
+BENCHMARK_CAPTURE(BM_SparseEntryGetResourceSparse, Large, sparse::R::string::foo_999);
-static void BM_SparseEntryGetResourceNotSparseLarge(benchmark::State& state) {
+static void BM_SparseEntryGetResourceNotSparse(benchmark::State& state, uint32_t resid) {
ResTable_config config;
memset(&config, 0, sizeof(config));
config.sdkVersion = 26;
- GetResourceBenchmarkOld({GetTestDataPath() + "/sparse/not_sparse.apk"}, &config,
- sparse::R::string::foo_999, state);
+ GetResourceBenchmark({GetTestDataPath() + "/sparse/not_sparse.apk"}, &config, resid, state);
}
-BENCHMARK(BM_SparseEntryGetResourceNotSparseLarge);
+BENCHMARK_CAPTURE(BM_SparseEntryGetResourceNotSparse, Small, sparse::R::integer::foo_9);
+BENCHMARK_CAPTURE(BM_SparseEntryGetResourceNotSparse, Large, sparse::R::string::foo_999);
} // namespace android
diff --git a/libs/androidfw/tests/data/unverified/R.h b/libs/androidfw/tests/data/unverified/R.h
deleted file mode 100644
index b734b49..0000000
--- a/libs/androidfw/tests/data/unverified/R.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2016 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 TESTS_DATA_UNVERIFIED_R_H_
-#define TESTS_DATA_UNVERIFIED_R_H_
-
-#include <cstdint>
-
-#include "tests/data/basic/R.h"
-
-namespace com {
-namespace android {
-
-namespace unverified = basic;
-
-} // namespace android
-} // namespace com
-
-#endif /* TESTS_DATA_UNVERIFIED_R_H_ */
diff --git a/libs/androidfw/tests/data/unverified/unverified.apk b/libs/androidfw/tests/data/unverified/unverified.apk
deleted file mode 100644
index 234b390..0000000
--- a/libs/androidfw/tests/data/unverified/unverified.apk
+++ /dev/null
Binary files differ
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 5c577ae..96e4fcf 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -417,3 +417,15 @@
"tests/microbench/TaskManagerBench.cpp",
],
}
+
+// ----------------------------------------
+// Phony target to build benchmarks for PGO
+// ----------------------------------------
+
+phony {
+ name: "pgo-targets-hwui",
+ required: [
+ "hwuimicro",
+ "hwuimacro",
+ ]
+}
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index d41db63..4243e7e 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -59,6 +59,7 @@
bool Properties::filterOutTestOverhead = false;
bool Properties::disableVsync = false;
bool Properties::skpCaptureEnabled = false;
+bool Properties::enableRTAnimations = true;
static int property_get_int(const char* key, int defaultValue) {
char buf[PROPERTY_VALUE_MAX] = {
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 9c30e4a..af4b694 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -255,6 +255,9 @@
static bool skpCaptureEnabled;
+ // For experimentation b/68769804
+ ANDROID_API static bool enableRTAnimations;
+
// Used for testing only to change the render pipeline.
static void overrideRenderPipelineType(RenderPipelineType);
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 508869a..eb0d161 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -738,6 +738,7 @@
// care of all alignment.
SkPaint paintCopy(paint);
paintCopy.setTextAlign(SkPaint::kLeft_Align);
+ SkASSERT(paintCopy.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
SkRect bounds =
SkRect::MakeLTRB(boundsLeft + x, boundsTop + y, boundsRight + x, boundsBottom + y);
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index ce00488..f118e8d 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -166,7 +166,7 @@
if (needsFill) {
paint.setStyle(SkPaint::Style::kFill_Style);
- paint.setAntiAlias(true);
+ paint.setAntiAlias(mAntiAlias);
outCanvas->drawPath(renderPath, paint);
}
@@ -182,7 +182,7 @@
}
if (needsStroke) {
paint.setStyle(SkPaint::Style::kStroke_Style);
- paint.setAntiAlias(true);
+ paint.setAntiAlias(mAntiAlias);
paint.setStrokeJoin(SkPaint::Join(properties.getStrokeLineJoin()));
paint.setStrokeCap(SkPaint::Cap(properties.getStrokeLineCap()));
paint.setStrokeMiter(properties.getStrokeMiterLimit());
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 7f75609..d9cf8ab 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -124,6 +124,7 @@
virtual void onPropertyChanged(Properties* properties) = 0;
virtual ~Node() {}
virtual void syncProperties() = 0;
+ virtual void setAntiAlias(bool aa) = 0;
protected:
std::string mName;
@@ -354,6 +355,7 @@
}
}
}
+ virtual void setAntiAlias(bool aa) { mAntiAlias = aa; }
protected:
const SkPath& getUpdatedPath(bool useStagingData, SkPath* tempStagingPath) override;
@@ -365,6 +367,8 @@
// Intermediate data for drawing, render thread only
SkPath mTrimmedSkPath;
+ // Default to use AntiAlias
+ bool mAntiAlias = true;
};
class ANDROID_API ClipPath : public Path {
@@ -373,6 +377,7 @@
ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
ClipPath() : Path() {}
void draw(SkCanvas* outCanvas, bool useStagingData) override;
+ virtual void setAntiAlias(bool aa) {}
};
class ANDROID_API Group : public Node {
@@ -476,6 +481,12 @@
}
}
+ virtual void setAntiAlias(bool aa) {
+ for (auto& child : mChildren) {
+ child->setAntiAlias(aa);
+ }
+ }
+
private:
GroupProperties mProperties = GroupProperties(this);
GroupProperties mStagingProperties = GroupProperties(this);
@@ -641,6 +652,8 @@
*/
void updateCache(sp<skiapipeline::VectorDrawableAtlas>& atlas, GrContext* context);
+ void setAntiAlias(bool aa) { mRootNode->setAntiAlias(aa); }
+
private:
class Cache {
public:
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 46d4ae7..e2f02df 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -110,7 +110,8 @@
// We only respect the nothingToDraw check when we are composing a layer. This
// ensures that we paint the layer even if it is not currently visible in the
// event that the properties change and it becomes visible.
- if (!renderNode->isRenderable() || (renderNode->nothingToDraw() && mComposeLayer)) {
+ if ((mProjectedDisplayList == nullptr && !renderNode->isRenderable()) ||
+ (renderNode->nothingToDraw() && mComposeLayer)) {
return;
}
@@ -204,7 +205,13 @@
if (layerNeedsPaint(layerProperties, alphaMultiplier, &tmpPaint)) {
paint = &tmpPaint;
}
- renderNode->getLayerSurface()->draw(canvas, 0, 0, paint);
+
+ // surfaces for layers are created on LAYER_SIZE boundaries (which are >= layer size) so
+ // we need to restrict the portion of the surface drawn to the size of the renderNode.
+ SkASSERT(renderNode->getLayerSurface()->width() >= bounds.width());
+ SkASSERT(renderNode->getLayerSurface()->height() >= bounds.height());
+ canvas->drawImageRect(renderNode->getLayerSurface()->makeImageSnapshot().get(),
+ bounds, bounds, paint);
if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) {
renderNode->getSkiaLayer()->hasRenderedSinceRepaint = true;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index d5fe7f4..4ba368f 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -161,14 +161,18 @@
bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
bool wideColorGamut) {
+ // compute the size of the surface (i.e. texture) to be allocated for this layer
+ const int surfaceWidth = ceilf(node->getWidth() / float(LAYER_SIZE)) * LAYER_SIZE;
+ const int surfaceHeight = ceilf(node->getHeight() / float(LAYER_SIZE)) * LAYER_SIZE;
+
SkSurface* layer = node->getLayerSurface();
- if (!layer || layer->width() != node->getWidth() || layer->height() != node->getHeight()) {
+ if (!layer || layer->width() != surfaceWidth || layer->height() != surfaceHeight) {
SkImageInfo info;
if (wideColorGamut) {
- info = SkImageInfo::Make(node->getWidth(), node->getHeight(), kRGBA_F16_SkColorType,
+ info = SkImageInfo::Make(surfaceWidth, surfaceHeight, kRGBA_F16_SkColorType,
kPremul_SkAlphaType);
} else {
- info = SkImageInfo::MakeN32Premul(node->getWidth(), node->getHeight());
+ info = SkImageInfo::MakeN32Premul(surfaceWidth, surfaceHeight);
}
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
SkASSERT(mRenderThread.getGrContext() != nullptr);
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index a33b287..5e89fae 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -17,7 +17,9 @@
#include "CacheManager.h"
#include "Layer.h"
+#include "Properties.h"
#include "RenderThread.h"
+#include "pipeline/skia/ShaderCache.h"
#include "renderstate/RenderState.h"
#include <GrContextOptions.h>
@@ -46,6 +48,9 @@
mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(
mMaxSurfaceArea / 2,
skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface);
+ if (Properties::isSkiaEnabled()) {
+ skiapipeline::ShaderCache::get().initShaderDiskCache();
+ }
}
void CacheManager::reset(GrContext* context) {
@@ -127,6 +132,8 @@
}
contextOptions->fExecutor = mTaskProcessor.get();
}
+
+ contextOptions->fPersistentCache = &skiapipeline::ShaderCache::get();
}
void CacheManager::trimMemory(TrimMemoryMode mode) {
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index b7bb2d15..820789d 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -34,6 +34,7 @@
#include "renderstate/Stencil.h"
#include "utils/GLUtils.h"
#include "utils/TimeUtils.h"
+#include "../Properties.h"
#include <cutils/properties.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -375,6 +376,9 @@
}
if (info.out.hasAnimations || !info.out.canDrawThisFrame) {
+ if (CC_UNLIKELY(!Properties::enableRTAnimations)) {
+ info.out.requiresUiRedraw = true;
+ }
if (!info.out.requiresUiRedraw) {
// If animationsNeedsRedraw is set don't bother posting for an RT anim
// as we will just end up fighting the UI thread.
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 05a9b75..20443ec 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -51,10 +51,17 @@
static bool gHasRenderThreadInstance = false;
+static void (*gOnStartHook)() = nullptr;
+
bool RenderThread::hasInstance() {
return gHasRenderThreadInstance;
}
+void RenderThread::setOnStartHook(void (*onStartHook)()) {
+ LOG_ALWAYS_FATAL_IF(hasInstance(), "can't set an onStartHook after we've started...");
+ gOnStartHook = onStartHook;
+}
+
RenderThread& RenderThread::getInstance() {
// This is a pointer because otherwise __cxa_finalize
// will try to delete it like a Good Citizen but that causes us to crash
@@ -256,6 +263,9 @@
bool RenderThread::threadLoop() {
setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY);
+ if (gOnStartHook) {
+ gOnStartHook();
+ }
initThreadLocals();
while (true) {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index d17a509..970537b 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -67,6 +67,9 @@
PREVENT_COPY_AND_ASSIGN(RenderThread);
public:
+ // Sets a callback that fires before any RenderThread setup has occured.
+ ANDROID_API static void setOnStartHook(void (*onStartHook)());
+
WorkQueue& queue() { return ThreadBase::queue(); }
// Mimics android.view.Choreographer
diff --git a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
index 58c9980..6bae80c 100644
--- a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
@@ -36,6 +36,7 @@
SkPaint textPaint;
textPaint.setTextSize(dp(20));
textPaint.setAntiAlias(true);
+ textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
TestUtils::drawUtf8ToCanvas(&canvas, "not that long long text", textPaint, dp(10), dp(30));
SkPoint pts[2];
diff --git a/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp b/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
index 75b231d..fee0659 100644
--- a/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
+++ b/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
@@ -42,8 +42,10 @@
mBluePaint.setColor(SkColorSetARGB(255, 0, 0, 255));
mBluePaint.setTextSize(padding);
+ mBluePaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
mGreenPaint.setColor(SkColorSetARGB(255, 0, 255, 0));
mGreenPaint.setTextSize(padding);
+ mGreenPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
// interleave drawText and drawRect with saveLayer ops
for (int i = 0; i < regions; i++, top += smallRectHeight) {
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index dff259f..c7f57fe 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -350,6 +350,72 @@
EXPECT_EQ(3, canvas.getIndex());
}
+RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, emptyReceiver) {
+ class ProjectionTestCanvas : public SkCanvas {
+ public:
+ ProjectionTestCanvas(int width, int height) : SkCanvas(width, height) {}
+ void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
+ mDrawCounter++;
+ }
+
+ int getDrawCounter() { return mDrawCounter; }
+
+ private:
+ int mDrawCounter = 0;
+ };
+
+ auto receiverBackground = TestUtils::createSkiaNode(
+ 0, 0, 100, 100,
+ [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
+ properties.setProjectionReceiver(true);
+ },
+ "B"); // a receiver with an empty display list
+
+ auto projectingRipple = TestUtils::createSkiaNode(
+ 0, 0, 100, 100,
+ [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
+ properties.setProjectBackwards(true);
+ properties.setClipToBounds(false);
+ SkPaint paint;
+ canvas.drawRect(0, 0, 100, 100, paint);
+ },
+ "P");
+ auto child = TestUtils::createSkiaNode(
+ 0, 0, 100, 100,
+ [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
+ SkPaint paint;
+ canvas.drawRect(0, 0, 100, 100, paint);
+ canvas.drawRenderNode(projectingRipple.get());
+ },
+ "C");
+ auto parent = TestUtils::createSkiaNode(
+ 0, 0, 100, 100,
+ [&receiverBackground, &child](RenderProperties& properties,
+ SkiaRecordingCanvas& canvas) {
+ canvas.drawRenderNode(receiverBackground.get());
+ canvas.drawRenderNode(child.get());
+ },
+ "A");
+ ContextFactory contextFactory;
+ std::unique_ptr<CanvasContext> canvasContext(
+ CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
+ TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
+ DamageAccumulator damageAccumulator;
+ info.damageAccumulator = &damageAccumulator;
+ parent->prepareTree(info);
+
+ // parent(A) -> (receiverBackground, child)
+ // child(C) -> (rect[0, 0, 100, 100], projectingRipple)
+ // projectingRipple(P) -> (rect[0, 0, 100, 100]) -> projects backwards
+ // receiverBackground(B) -> (empty) -> projection receiver
+
+ // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
+ ProjectionTestCanvas canvas(100, 100);
+ RenderNodeDrawable drawable(parent.get(), &canvas, true);
+ canvas.drawDrawable(&drawable);
+ EXPECT_EQ(2, canvas.getDrawCounter());
+}
+
RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, projectionHwLayer) {
/* R is backward projected on B and C is a layer.
A
@@ -394,15 +460,15 @@
ProjectionLayer(int* drawCounter)
: SkSurface_Base(SkImageInfo::MakeN32Premul(LAYER_WIDTH, LAYER_HEIGHT), nullptr)
, mDrawCounter(drawCounter) {}
- void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override {
+ virtual sk_sp<SkImage> onNewImageSnapshot() override {
EXPECT_EQ(3, (*mDrawCounter)++);
EXPECT_EQ(SkRect::MakeLTRB(100 - SCROLL_X, 100 - SCROLL_Y, 300 - SCROLL_X,
300 - SCROLL_Y),
TestUtils::getClipBounds(this->getCanvas()));
+ return nullptr;
}
SkCanvas* onNewCanvas() override { return new ProjectionTestCanvas(mDrawCounter); }
sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override { return nullptr; }
- sk_sp<SkImage> onNewImageSnapshot() override { return nullptr; }
void onCopyOnWrite(ContentChangeMode) override {}
int* mDrawCounter;
};
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index a92cbfd..e7496f7 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -85,32 +85,8 @@
outPath->rCubicTo(8.0, 8.0, 8.0, 8.0, 8.0, 8.0);
outPath->cubicTo(16.0, 16.0, 9.0, 9.0, 9.0, 9.0);
outPath->rCubicTo(0.0, 0.0, 9.0, 9.0, 9.0, 9.0);
- outPath->cubicTo(18.447775037328352, 20.404243860300607, 17.998389141249767,
- 22.8911717921705, 16.737515350332117, 24.986664170401575);
- outPath->cubicTo(15.476641559414468, 27.08215654863265, 13.489843598291483,
- 28.644011882390082, 11.155893964798905, 29.37447073281729);
- outPath->cubicTo(8.821944331306327, 30.1049295832445, 6.299226382436471,
- 29.954422532383525, 4.0686829203897235, 28.951642951534332);
- outPath->cubicTo(1.838139458342976, 27.94886337068514, 0.05113662931485696,
- 26.161860541657013, -0.9516429515343354, 23.931317079610267);
- outPath->cubicTo(-1.9544225323835278, 21.70077361756352, -2.1049295832444987,
- 19.178055668693663, -1.37447073281729, 16.844106035201087);
- outPath->cubicTo(-0.6440118823900814, 14.51015640170851, 0.9178434513673546,
- 12.523358440585524, 3.0133358295984305, 11.262484649667876);
- outPath->cubicTo(5.108828207829506, 10.001610858750228, 7.5957561396993984,
- 9.552224962671648, 10.000000000000005, 10.0);
- outPath->cubicTo(10.0, 7.348852265086975, 11.054287646850167, 4.803576729418881,
- 12.928932188134523, 2.9289321881345254);
- outPath->cubicTo(14.803576729418879, 1.0542876468501696, 17.348852265086972,
- 4.870079381441987E-16, 19.999999999999996, 0.0);
- outPath->cubicTo(22.65114773491302, -4.870079381441987E-16, 25.19642327058112,
- 1.0542876468501678, 27.071067811865476, 2.9289321881345227);
- outPath->cubicTo(28.94571235314983, 4.803576729418878, 30.0, 7.348852265086974, 30.0,
- 9.999999999999998);
- outPath->cubicTo(30.0, 12.651147734913023, 28.94571235314983, 15.19642327058112,
- 27.071067811865476, 17.071067811865476);
- outPath->cubicTo(25.19642327058112, 18.94571235314983, 22.651147734913028, 20.0,
- 20.000000000000004, 20.0);
+ outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 10.0, 10.0);
+ outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 20.0, 20.0);
}},
// Check box VectorDrawable path data
@@ -181,22 +157,7 @@
},
[](SkPath* outPath) {
outPath->moveTo(300.0, 70.0);
- outPath->cubicTo(239.06697794203706, 70.13246340443499, 180.6164396449267,
- 94.47383115953485, 137.6004913602211, 137.6302781499585);
- outPath->cubicTo(94.58454307551551, 180.78672514038215, 70.43390412842275,
- 239.3163266242308, 70.50013586976587, 300.2494566687817);
- outPath->cubicTo(70.56636761110899, 361.1825867133326, 94.84418775550249,
- 419.65954850554147, 137.9538527586204, 462.72238058830936);
- outPath->cubicTo(181.06351776173827, 505.7852126710772, 239.5668339599056,
- 529.999456521097, 300.49999999999994, 529.999456521097);
- outPath->cubicTo(361.43316604009436, 529.999456521097, 419.93648223826176,
- 505.78521267107726, 463.0461472413797, 462.7223805883093);
- outPath->cubicTo(506.1558122444976, 419.65954850554135, 530.433632388891,
- 361.1825867133324, 530.4998641302341, 300.2494566687815);
- outPath->cubicTo(530.5660958715771, 239.31632662423056, 506.4154569244844,
- 180.7867251403819, 463.3995086397787, 137.6302781499583);
- outPath->cubicTo(420.383560355073, 94.47383115953468, 361.93302205796255,
- 70.13246340443492, 300.9999999999996, 70.00000000000003);
+ outPath->arcTo(230.0, 230.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCCW_Direction, 301.0, 70.0);
outPath->close();
outPath->moveTo(300.0, 70.0);
}},
diff --git a/libs/hwui/thread/ThreadBase.h b/libs/hwui/thread/ThreadBase.h
index b3fec1f..8068121 100644
--- a/libs/hwui/thread/ThreadBase.h
+++ b/libs/hwui/thread/ThreadBase.h
@@ -31,7 +31,10 @@
PREVENT_COPY_AND_ASSIGN(ThreadBase);
public:
- ThreadBase() : mLooper(new Looper(false)), mQueue([this]() { mLooper->wake(); }, mLock) {}
+ ThreadBase()
+ : Thread(false)
+ , mLooper(new Looper(false))
+ , mQueue([this]() { mLooper->wake(); }, mLock) {}
WorkQueue& queue() { return mQueue; }
diff --git a/libs/hwui/utils/VectorDrawableUtils.cpp b/libs/hwui/utils/VectorDrawableUtils.cpp
index 1931d64..6b8f315 100644
--- a/libs/hwui/utils/VectorDrawableUtils.cpp
+++ b/libs/hwui/utils/VectorDrawableUtils.cpp
@@ -96,132 +96,6 @@
}
}
-/**
- * Converts an arc to cubic Bezier segments and records them in p.
- *
- * @param p The target for the cubic Bezier segments
- * @param cx The x coordinate center of the ellipse
- * @param cy The y coordinate center of the ellipse
- * @param a The radius of the ellipse in the horizontal direction
- * @param b The radius of the ellipse in the vertical direction
- * @param e1x E(eta1) x coordinate of the starting point of the arc
- * @param e1y E(eta2) y coordinate of the starting point of the arc
- * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane
- * @param start The start angle of the arc on the ellipse
- * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
- */
-static void arcToBezier(SkPath* p, double cx, double cy, double a, double b, double e1x, double e1y,
- double theta, double start, double sweep) {
- // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html
- // and http://www.spaceroots.org/documents/ellipse/node22.html
-
- // Maximum of 45 degrees per cubic Bezier segment
- int numSegments = ceil(fabs(sweep * 4 / M_PI));
-
- double eta1 = start;
- double cosTheta = cos(theta);
- double sinTheta = sin(theta);
- double cosEta1 = cos(eta1);
- double sinEta1 = sin(eta1);
- double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1);
- double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1);
-
- double anglePerSegment = sweep / numSegments;
- for (int i = 0; i < numSegments; i++) {
- double eta2 = eta1 + anglePerSegment;
- double sinEta2 = sin(eta2);
- double cosEta2 = cos(eta2);
- double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2);
- double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2);
- double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2;
- double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2;
- double tanDiff2 = tan((eta2 - eta1) / 2);
- double alpha = sin(eta2 - eta1) * (sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3;
- double q1x = e1x + alpha * ep1x;
- double q1y = e1y + alpha * ep1y;
- double q2x = e2x - alpha * ep2x;
- double q2y = e2y - alpha * ep2y;
-
- p->cubicTo((float)q1x, (float)q1y, (float)q2x, (float)q2y, (float)e2x, (float)e2y);
- eta1 = eta2;
- e1x = e2x;
- e1y = e2y;
- ep1x = ep2x;
- ep1y = ep2y;
- }
-}
-
-inline double toRadians(float theta) {
- return theta * M_PI / 180;
-}
-
-static void drawArc(SkPath* p, float x0, float y0, float x1, float y1, float a, float b,
- float theta, bool isMoreThanHalf, bool isPositiveArc) {
- /* Convert rotation angle from degrees to radians */
- double thetaD = toRadians(theta);
- /* Pre-compute rotation matrix entries */
- double cosTheta = cos(thetaD);
- double sinTheta = sin(thetaD);
- /* Transform (x0, y0) and (x1, y1) into unit space */
- /* using (inverse) rotation, followed by (inverse) scale */
- double x0p = (x0 * cosTheta + y0 * sinTheta) / a;
- double y0p = (-x0 * sinTheta + y0 * cosTheta) / b;
- double x1p = (x1 * cosTheta + y1 * sinTheta) / a;
- double y1p = (-x1 * sinTheta + y1 * cosTheta) / b;
-
- /* Compute differences and averages */
- double dx = x0p - x1p;
- double dy = y0p - y1p;
- double xm = (x0p + x1p) / 2;
- double ym = (y0p + y1p) / 2;
- /* Solve for intersecting unit circles */
- double dsq = dx * dx + dy * dy;
- if (dsq == 0.0) {
- VECTOR_DRAWABLE_LOGD("Points are coincident");
- return; /* Points are coincident */
- }
- double disc = 1.0 / dsq - 1.0 / 4.0;
- if (disc < 0.0) {
- VECTOR_DRAWABLE_LOGD("Points are too far apart %f", dsq);
- float adjust = (float)(sqrt(dsq) / 1.99999);
- drawArc(p, x0, y0, x1, y1, a * adjust, b * adjust, theta, isMoreThanHalf, isPositiveArc);
- return; /* Points are too far apart */
- }
- double s = sqrt(disc);
- double sdx = s * dx;
- double sdy = s * dy;
- double cx;
- double cy;
- if (isMoreThanHalf == isPositiveArc) {
- cx = xm - sdy;
- cy = ym + sdx;
- } else {
- cx = xm + sdy;
- cy = ym - sdx;
- }
-
- double eta0 = atan2((y0p - cy), (x0p - cx));
-
- double eta1 = atan2((y1p - cy), (x1p - cx));
-
- double sweep = (eta1 - eta0);
- if (isPositiveArc != (sweep >= 0)) {
- if (sweep > 0) {
- sweep -= 2 * M_PI;
- } else {
- sweep += 2 * M_PI;
- }
- }
-
- cx *= a;
- cy *= b;
- double tcx = cx;
- cx = cx * cosTheta - cy * sinTheta;
- cy = tcx * sinTheta + cy * cosTheta;
-
- arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep);
-}
-
// Use the given verb, and points in the range [start, end) to insert a command into the SkPath.
void PathResolver::addCommand(SkPath* outPath, char previousCmd, char cmd,
const std::vector<float>* points, size_t start, size_t end) {
@@ -424,18 +298,20 @@
break;
case 'a': // Draws an elliptical arc
// (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
- drawArc(outPath, currentX, currentY, points->at(k + 5) + currentX,
- points->at(k + 6) + currentY, points->at(k + 0), points->at(k + 1),
- points->at(k + 2), points->at(k + 3) != 0, points->at(k + 4) != 0);
+ outPath->arcTo(points->at(k + 0), points->at(k + 1), points->at(k + 2),
+ (SkPath::ArcSize) (points->at(k + 3) != 0),
+ (SkPath::Direction) (points->at(k + 4) == 0),
+ points->at(k + 5) + currentX, points->at(k + 6) + currentY);
currentX += points->at(k + 5);
currentY += points->at(k + 6);
ctrlPointX = currentX;
ctrlPointY = currentY;
break;
case 'A': // Draws an elliptical arc
- drawArc(outPath, currentX, currentY, points->at(k + 5), points->at(k + 6),
- points->at(k + 0), points->at(k + 1), points->at(k + 2),
- points->at(k + 3) != 0, points->at(k + 4) != 0);
+ outPath->arcTo(points->at(k + 0), points->at(k + 1), points->at(k + 2),
+ (SkPath::ArcSize) (points->at(k + 3) != 0),
+ (SkPath::Direction) (points->at(k + 4) == 0),
+ points->at(k + 5), points->at(k + 6));
currentX = points->at(k + 5);
currentY = points->at(k + 6);
ctrlPointX = currentX;
diff --git a/libs/incident/include/android/os/IncidentReportArgs.h b/libs/incident/include/android/os/IncidentReportArgs.h
index da80989..2849d58 100644
--- a/libs/incident/include/android/os/IncidentReportArgs.h
+++ b/libs/incident/include/android/os/IncidentReportArgs.h
@@ -29,6 +29,12 @@
using namespace std;
+// DESTINATION enum value, sync with proto/android/privacy.proto
+const uint8_t DEST_LOCAL = 0;
+const uint8_t DEST_EXPLICIT = 100;
+const uint8_t DEST_AUTOMATIC = 200;
+
+
class IncidentReportArgs : public Parcelable {
public:
IncidentReportArgs();
@@ -41,19 +47,19 @@
void setAll(bool all);
void setDest(int dest);
void addSection(int section);
- void addHeader(const vector<int8_t>& header);
+ void addHeader(const vector<uint8_t>& header);
inline bool all() const { return mAll; }
bool containsSection(int section) const;
inline int dest() const { return mDest; }
inline const set<int>& sections() const { return mSections; }
- inline const vector<vector<int8_t>>& headers() const { return mHeaders; }
+ inline const vector<vector<uint8_t>>& headers() const { return mHeaders; }
void merge(const IncidentReportArgs& that);
private:
set<int> mSections;
- vector<vector<int8_t>> mHeaders;
+ vector<vector<uint8_t>> mHeaders;
bool mAll;
int mDest;
};
diff --git a/libs/incident/proto/android/privacy.proto b/libs/incident/proto/android/privacy.proto
index 5fd75d6..7590b22 100644
--- a/libs/incident/proto/android/privacy.proto
+++ b/libs/incident/proto/android/privacy.proto
@@ -34,21 +34,23 @@
// Fields or messages annotated with DEST_EXPLICIT can be sent
// off the device with an explicit user action.
- DEST_EXPLICIT = 1;
+ DEST_EXPLICIT = 100;
// Fields or messages annotated with DEST_AUTOMATIC can be sent by
// automatic means, without per-sending user consent. The user
// still must have previously accepted a consent to share this
// information.
- DEST_AUTOMATIC = 2;
+ DEST_AUTOMATIC = 200;
- // There is no more permissive option than DEST_AUTOMATIC.
+ // This is the default value, which could be overridden by other values.
+ // The reason to pick 255 is it fits into one byte.
+ DEST_UNSET = 255;
+
+ // Currently use 0, 100, 200 and 255, values in between are reserved for futures.
}
message PrivacyFlags {
- optional Destination dest = 1 [
- default = DEST_EXPLICIT
- ];
+ optional Destination dest = 1 [ default = DEST_UNSET ];
// regex to filter pii sensitive info from a string field type
repeated string patterns = 2;
@@ -58,3 +60,8 @@
// Flags for automatically filtering statistics
optional PrivacyFlags privacy = 102672883;
}
+
+extend google.protobuf.MessageOptions {
+ // Flags used to annotate a message which all its unset primitive types inhert this tag.
+ optional PrivacyFlags msg_privacy = 102672883;
+}
diff --git a/libs/incident/src/IncidentReportArgs.cpp b/libs/incident/src/IncidentReportArgs.cpp
index e628722..bd9c8ee 100644
--- a/libs/incident/src/IncidentReportArgs.cpp
+++ b/libs/incident/src/IncidentReportArgs.cpp
@@ -69,7 +69,7 @@
return err;
}
- for (vector<vector<int8_t>>::const_iterator it = mHeaders.begin(); it != mHeaders.end(); it++) {
+ for (vector<vector<uint8_t>>::const_iterator it = mHeaders.begin(); it != mHeaders.end(); it++) {
err = out->writeByteVector(*it);
if (err != NO_ERROR) {
return err;
@@ -161,7 +161,7 @@
}
void
-IncidentReportArgs::addHeader(const vector<int8_t>& header)
+IncidentReportArgs::addHeader(const vector<uint8_t>& header)
{
mHeaders.push_back(header);
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 968f596..d15ab33 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -184,6 +184,17 @@
public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
/**
+ * Broadcast intent action when {@link android.provider.Settings.Secure#LOCATION_MODE} is
+ * about to be changed through Settings app or Quick Settings.
+ * For use with the {@link android.provider.Settings.Secure#LOCATION_MODE} API.
+ * If you're interacting with {@link #isProviderEnabled(String)}, use
+ * {@link #PROVIDERS_CHANGED_ACTION} instead.
+ *
+ * @hide
+ */
+ public static final String MODE_CHANGING_ACTION = "com.android.settings.location.MODE_CHANGING";
+
+ /**
* Broadcast intent action indicating that the GPS has either started or
* stopped receiving GPS fixes. An intent extra provides this state as a
* boolean, where {@code true} means that the GPS is actively receiving fixes.
diff --git a/location/tests/Android.mk b/location/tests/Android.mk
new file mode 100644
index 0000000..57848f3
--- /dev/null
+++ b/location/tests/Android.mk
@@ -0,0 +1,3 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
\ No newline at end of file
diff --git a/location/tests/locationtests/Android.mk b/location/tests/locationtests/Android.mk
index 73b2bb5..44d290e 100644
--- a/location/tests/locationtests/Android.mk
+++ b/location/tests/locationtests/Android.mk
@@ -7,7 +7,7 @@
# Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_PACKAGE_NAME := FrameworksLocationTests
LOCAL_STATIC_JAVA_LIBRARIES := \
diff --git a/lowpan/tests/Android.mk b/lowpan/tests/Android.mk
index bb0a944..99499dc 100644
--- a/lowpan/tests/Android.mk
+++ b/lowpan/tests/Android.mk
@@ -56,6 +56,7 @@
LOCAL_JAVA_LIBRARIES := \
android.test.runner \
+ android.test.base \
LOCAL_PACKAGE_NAME := FrameworksLowpanApiTests
LOCAL_COMPATIBILITY_SUITE := device-tests
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 7afe267..e0289f0 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -741,7 +741,7 @@
/**
* @hide
* Same as {@link #setCapturePreset(int)} but authorizes the use of HOTWORD,
- * REMOTE_SUBMIX and RADIO_TUNER.
+ * REMOTE_SUBMIX, RADIO_TUNER, VOICE_DOWNLINK, VOICE_UPLINK and VOICE_CALL.
* @param preset
* @return the same Builder instance.
*/
@@ -749,7 +749,10 @@
public Builder setInternalCapturePreset(int preset) {
if ((preset == MediaRecorder.AudioSource.HOTWORD)
|| (preset == MediaRecorder.AudioSource.REMOTE_SUBMIX)
- || (preset == MediaRecorder.AudioSource.RADIO_TUNER)) {
+ || (preset == MediaRecorder.AudioSource.RADIO_TUNER)
+ || (preset == MediaRecorder.AudioSource.VOICE_DOWNLINK)
+ || (preset == MediaRecorder.AudioSource.VOICE_UPLINK)
+ || (preset == MediaRecorder.AudioSource.VOICE_CALL)) {
mSource = preset;
} else {
setCapturePreset(preset);
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 0906ba5..27784e9 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -1516,66 +1516,13 @@
}
/**
- * Helper class to handle the forwarding of native events to the appropriate listener
- * (potentially) handled in a different thread
- */
- private class NativeRoutingEventHandlerDelegate {
- private final Handler mHandler;
-
- NativeRoutingEventHandlerDelegate(final AudioRecord record,
- final AudioRouting.OnRoutingChangedListener listener,
- Handler handler) {
- // find the looper for our new event handler
- Looper looper;
- if (handler != null) {
- looper = handler.getLooper();
- } else {
- // no given handler, use the looper the AudioRecord was created in
- looper = mInitializationLooper;
- }
-
- // construct the event handler with this looper
- if (looper != null) {
- // implement the event handler delegate
- mHandler = new Handler(looper) {
- @Override
- public void handleMessage(Message msg) {
- if (record == null) {
- return;
- }
- switch(msg.what) {
- case AudioSystem.NATIVE_EVENT_ROUTING_CHANGE:
- if (listener != null) {
- listener.onRoutingChanged(record);
- }
- break;
- default:
- loge("Unknown native event type: " + msg.what);
- break;
- }
- }
- };
- } else {
- mHandler = null;
- }
- }
-
- Handler getHandler() {
- return mHandler;
- }
- }
-
- /**
* Sends device list change notification to all listeners.
*/
private void broadcastRoutingChange() {
AudioManager.resetAudioPortGeneration();
synchronized (mRoutingChangeListeners) {
for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) {
- Handler handler = delegate.getHandler();
- if (handler != null) {
- handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
- }
+ delegate.notifyClient();
}
}
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 50145f8..e535fdf 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -2856,10 +2856,7 @@
AudioManager.resetAudioPortGeneration();
synchronized (mRoutingChangeListeners) {
for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) {
- Handler handler = delegate.getHandler();
- if (handler != null) {
- handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
- }
+ delegate.notifyClient();
}
}
}
@@ -2943,56 +2940,6 @@
}
}
- /**
- * Helper class to handle the forwarding of native events to the appropriate listener
- * (potentially) handled in a different thread
- */
- private class NativeRoutingEventHandlerDelegate {
- private final Handler mHandler;
-
- NativeRoutingEventHandlerDelegate(final AudioTrack track,
- final AudioRouting.OnRoutingChangedListener listener,
- Handler handler) {
- // find the looper for our new event handler
- Looper looper;
- if (handler != null) {
- looper = handler.getLooper();
- } else {
- // no given handler, use the looper the AudioTrack was created in
- looper = mInitializationLooper;
- }
-
- // construct the event handler with this looper
- if (looper != null) {
- // implement the event handler delegate
- mHandler = new Handler(looper) {
- @Override
- public void handleMessage(Message msg) {
- if (track == null) {
- return;
- }
- switch(msg.what) {
- case AudioSystem.NATIVE_EVENT_ROUTING_CHANGE:
- if (listener != null) {
- listener.onRoutingChanged(track);
- }
- break;
- default:
- loge("Unknown native event type: " + msg.what);
- break;
- }
- }
- };
- } else {
- mHandler = null;
- }
- }
-
- Handler getHandler() {
- return mHandler;
- }
- }
-
//---------------------------------------------------------
// Methods for IPlayer interface
//--------------------
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index c78c99f..1019580 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -640,7 +640,6 @@
* The ImageReader continues to be usable after this call, but may need to reallocate buffers
* when more buffers are needed for rendering.
* </p>
- * @hide
*/
public void discardFreeBuffers() {
synchronized (mCloseLock) {
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 0b86401..745eb74d 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -226,9 +226,12 @@
/**
* Call this method after setDataSource(). This method finds a
* representative frame close to the given time position by considering
- * the given option if possible, and returns it as a bitmap. This is
- * useful for generating a thumbnail for an input data source or just
- * obtain and display a frame at the given time position.
+ * the given option if possible, and returns it as a bitmap.
+ *
+ * <p>If you don't need a full-resolution
+ * frame (for example, because you need a thumbnail image), use
+ * {@link #getScaledFrameAtTime getScaledFrameAtTime()} instead of this
+ * method.</p>
*
* @param timeUs The time position where the frame will be retrieved.
* When retrieving the frame at the given time position, there is no
@@ -315,11 +318,15 @@
/**
* Call this method after setDataSource(). This method finds a
* representative frame close to the given time position if possible,
- * and returns it as a bitmap. This is useful for generating a thumbnail
- * for an input data source. Call this method if one does not care
+ * and returns it as a bitmap. Call this method if one does not care
* how the frame is found as long as it is close to the given time;
* otherwise, please call {@link #getFrameAtTime(long, int)}.
*
+ * <p>If you don't need a full-resolution
+ * frame (for example, because you need a thumbnail image), use
+ * {@link #getScaledFrameAtTime getScaledFrameAtTime()} instead of this
+ * method.</p>
+ *
* @param timeUs The time position where the frame will be retrieved.
* When retrieving the frame at the given time position, there is no
* guarentee that the data source has a frame located at the position.
@@ -339,11 +346,15 @@
/**
* Call this method after setDataSource(). This method finds a
* representative frame at any time position if possible,
- * and returns it as a bitmap. This is useful for generating a thumbnail
- * for an input data source. Call this method if one does not
+ * and returns it as a bitmap. Call this method if one does not
* care about where the frame is located; otherwise, please call
* {@link #getFrameAtTime(long)} or {@link #getFrameAtTime(long, int)}
*
+ * <p>If you don't need a full-resolution
+ * frame (for example, because you need a thumbnail image), use
+ * {@link #getScaledFrameAtTime getScaledFrameAtTime()} instead of this
+ * method.</p>
+ *
* @return A Bitmap containing a representative video frame, which
* can be null, if such a frame cannot be retrieved.
*
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 649c091..1bc3dfa 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1514,7 +1514,8 @@
if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
enableNativeRoutingCallbacksLocked(true);
mRoutingChangeListeners.put(
- listener, new NativeRoutingEventHandlerDelegate(this, listener, handler));
+ listener, new NativeRoutingEventHandlerDelegate(this, listener,
+ handler != null ? handler : mEventHandler));
}
}
}
@@ -1535,36 +1536,6 @@
}
}
- /**
- * Helper class to handle the forwarding of native events to the appropriate listener
- * (potentially) handled in a different thread
- */
- private class NativeRoutingEventHandlerDelegate {
- private MediaPlayer mMediaPlayer;
- private AudioRouting.OnRoutingChangedListener mOnRoutingChangedListener;
- private Handler mHandler;
-
- NativeRoutingEventHandlerDelegate(final MediaPlayer mediaPlayer,
- final AudioRouting.OnRoutingChangedListener listener, Handler handler) {
- mMediaPlayer = mediaPlayer;
- mOnRoutingChangedListener = listener;
- mHandler = handler != null ? handler : mEventHandler;
- }
-
- void notifyClient() {
- if (mHandler != null) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (mOnRoutingChangedListener != null) {
- mOnRoutingChangedListener.onRoutingChanged(mMediaPlayer);
- }
- }
- });
- }
- }
- }
-
private native final boolean native_setOutputDevice(int deviceId);
private native final int native_getRoutedDeviceId();
private native final void native_enableDeviceCallback(boolean enabled);
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 7678490..3c49b80 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -25,6 +25,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
+import android.util.ArrayMap;
import android.util.Log;
import android.view.Surface;
@@ -34,6 +35,8 @@
import java.io.RandomAccessFile;
import java.lang.ref.WeakReference;
+import com.android.internal.annotations.GuardedBy;
+
/**
* Used to record audio and video. The recording control is based on a
* simple state machine (see below).
@@ -76,7 +79,7 @@
* <a href="{@docRoot}guide/topics/media/audio-capture.html">Audio Capture</a> developer guide.</p>
* </div>
*/
-public class MediaRecorder
+public class MediaRecorder implements AudioRouting
{
static {
System.loadLibrary("media_jni");
@@ -1243,6 +1246,7 @@
private static final int MEDIA_RECORDER_TRACK_EVENT_INFO = 101;
private static final int MEDIA_RECORDER_TRACK_EVENT_LIST_END = 1000;
+ private static final int MEDIA_RECORDER_AUDIO_ROUTING_CHANGED = 10000;
@Override
public void handleMessage(Message msg) {
@@ -1265,6 +1269,16 @@
return;
+ case MEDIA_RECORDER_AUDIO_ROUTING_CHANGED:
+ AudioManager.resetAudioPortGeneration();
+ synchronized (mRoutingChangeListeners) {
+ for (NativeRoutingEventHandlerDelegate delegate
+ : mRoutingChangeListeners.values()) {
+ delegate.notifyClient();
+ }
+ }
+ return;
+
default:
Log.e(TAG, "Unknown message type " + msg.what);
return;
@@ -1272,6 +1286,155 @@
}
}
+ //--------------------------------------------------------------------------
+ // Explicit Routing
+ //--------------------
+ private AudioDeviceInfo mPreferredDevice = null;
+
+ /**
+ * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route
+ * the input from this MediaRecorder.
+ * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio source.
+ * If deviceInfo is null, default routing is restored.
+ * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and
+ * does not correspond to a valid audio input device.
+ */
+ @Override
+ public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) {
+ if (deviceInfo != null && !deviceInfo.isSource()) {
+ return false;
+ }
+ int preferredDeviceId = deviceInfo != null ? deviceInfo.getId() : 0;
+ boolean status = native_setInputDevice(preferredDeviceId);
+ if (status == true) {
+ synchronized (this) {
+ mPreferredDevice = deviceInfo;
+ }
+ }
+ return status;
+ }
+
+ /**
+ * Returns the selected input device specified by {@link #setPreferredDevice}. Note that this
+ * is not guaranteed to correspond to the actual device being used for recording.
+ */
+ @Override
+ public AudioDeviceInfo getPreferredDevice() {
+ synchronized (this) {
+ return mPreferredDevice;
+ }
+ }
+
+ /**
+ * Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaRecorder
+ * Note: The query is only valid if the MediaRecorder is currently recording.
+ * If the recorder is not recording, the returned device can be null or correspond to previously
+ * selected device when the recorder was last active.
+ */
+ @Override
+ public AudioDeviceInfo getRoutedDevice() {
+ int deviceId = native_getRoutedDeviceId();
+ if (deviceId == 0) {
+ return null;
+ }
+ AudioDeviceInfo[] devices =
+ AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
+ for (int i = 0; i < devices.length; i++) {
+ if (devices[i].getId() == deviceId) {
+ return devices[i];
+ }
+ }
+ return null;
+ }
+
+ /*
+ * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
+ */
+ private void enableNativeRoutingCallbacksLocked(boolean enabled) {
+ if (mRoutingChangeListeners.size() == 0) {
+ native_enableDeviceCallback(enabled);
+ }
+ }
+
+ /**
+ * The list of AudioRouting.OnRoutingChangedListener interfaces added (with
+ * {@link #addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, Handler)}
+ * by an app to receive (re)routing notifications.
+ */
+ @GuardedBy("mRoutingChangeListeners")
+ private ArrayMap<AudioRouting.OnRoutingChangedListener,
+ NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
+
+ /**
+ * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
+ * changes on this MediaRecorder.
+ * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
+ * notifications of rerouting events.
+ * @param handler Specifies the {@link Handler} object for the thread on which to execute
+ * the callback. If <code>null</code>, the handler on the main looper will be used.
+ */
+ @Override
+ public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
+ Handler handler) {
+ synchronized (mRoutingChangeListeners) {
+ if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
+ enableNativeRoutingCallbacksLocked(true);
+ mRoutingChangeListeners.put(
+ listener, new NativeRoutingEventHandlerDelegate(this, listener, handler));
+ }
+ }
+ }
+
+ /**
+ * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
+ * to receive rerouting notifications.
+ * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
+ * to remove.
+ */
+ @Override
+ public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
+ synchronized (mRoutingChangeListeners) {
+ if (mRoutingChangeListeners.containsKey(listener)) {
+ mRoutingChangeListeners.remove(listener);
+ enableNativeRoutingCallbacksLocked(false);
+ }
+ }
+ }
+
+ /**
+ * Helper class to handle the forwarding of native events to the appropriate listener
+ * (potentially) handled in a different thread
+ */
+ private class NativeRoutingEventHandlerDelegate {
+ private MediaRecorder mMediaRecorder;
+ private AudioRouting.OnRoutingChangedListener mOnRoutingChangedListener;
+ private Handler mHandler;
+
+ NativeRoutingEventHandlerDelegate(final MediaRecorder mediaRecorder,
+ final AudioRouting.OnRoutingChangedListener listener, Handler handler) {
+ mMediaRecorder = mediaRecorder;
+ mOnRoutingChangedListener = listener;
+ mHandler = handler != null ? handler : mEventHandler;
+ }
+
+ void notifyClient() {
+ if (mHandler != null) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mOnRoutingChangedListener != null) {
+ mOnRoutingChangedListener.onRoutingChanged(mMediaRecorder);
+ }
+ }
+ });
+ }
+ }
+ }
+
+ private native final boolean native_setInputDevice(int deviceId);
+ private native final int native_getRoutedDeviceId();
+ private native final void native_enableDeviceCallback(boolean enabled);
+
/**
* Called from native code when an interesting event happens. This method
* just uses the EventHandler system to post the event back to the main app thread.
diff --git a/media/java/android/media/NativeRoutingEventHandlerDelegate.java b/media/java/android/media/NativeRoutingEventHandlerDelegate.java
new file mode 100644
index 0000000..9a6baf1
--- /dev/null
+++ b/media/java/android/media/NativeRoutingEventHandlerDelegate.java
@@ -0,0 +1,51 @@
+/*
+ * 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 android.media;
+
+import android.os.Handler;
+
+/**
+ * Helper class {@link AudioTrack}, {@link AudioRecord}, {@link MediaPlayer} and {@link MediaRecorder}
+ * to handle the forwarding of native events to the appropriate listener
+ * (potentially) handled in a different thread.
+ * @hide
+ */
+class NativeRoutingEventHandlerDelegate {
+ private AudioRouting mAudioRouting;
+ private AudioRouting.OnRoutingChangedListener mOnRoutingChangedListener;
+ private Handler mHandler;
+
+ NativeRoutingEventHandlerDelegate(final AudioRouting audioRouting,
+ final AudioRouting.OnRoutingChangedListener listener, Handler handler) {
+ mAudioRouting = audioRouting;
+ mOnRoutingChangedListener = listener;
+ mHandler = handler;
+ }
+
+ void notifyClient() {
+ if (mHandler != null) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mOnRoutingChangedListener != null) {
+ mOnRoutingChangedListener.onRoutingChanged(mAudioRouting);
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 6c87a9d..143182f 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -1586,8 +1586,10 @@
* @param info The TV input which will use the acquired Hardware.
* @return Hardware on success, {@code null} otherwise.
*
+ * @hide
* @removed
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
public Hardware acquireTvInputHardware(int deviceId, final HardwareCallback callback,
TvInputInfo info) {
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index aaf18e7..ba29d2d 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -423,6 +423,12 @@
}
}
+ private void doScanDirectory(String path) {
+ String[] scanPath;
+ scanPath = new String[] { path };
+ mMediaScanner.scanDirectories(scanPath);
+ }
+
private Cursor createObjectQuery(int storageID, int format, int parent) throws RemoteException {
String where;
String[] whereArgs;
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 497684c..d2bc174 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -657,6 +657,56 @@
return mybundle;
}
+
+static jboolean
+android_media_MediaRecorder_setInputDevice(JNIEnv *env, jobject thiz, jint device_id)
+{
+ ALOGV("android_media_MediaRecorder_setInputDevice");
+
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
+ if (mr == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return false;
+ }
+
+ if (process_media_recorder_call(env, mr->setInputDevice(device_id),
+ "java/lang/RuntimeException", "setInputDevice failed.")) {
+ return false;
+ }
+ return true;
+}
+
+static jint
+android_media_MediaRecorder_getRoutedDeviceId(JNIEnv *env, jobject thiz)
+{
+ ALOGV("android_media_MediaRecorder_getRoutedDeviceId");
+
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
+ if (mr == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return AUDIO_PORT_HANDLE_NONE;
+ }
+
+ audio_port_handle_t deviceId;
+ process_media_recorder_call(env, mr->getRoutedDeviceId(&deviceId),
+ "java/lang/RuntimeException", "getRoutedDeviceId failed.");
+ return (jint) deviceId;
+}
+
+static void
+android_media_MediaRecorder_enableDeviceCallback(JNIEnv *env, jobject thiz, jboolean enabled)
+{
+ ALOGV("android_media_MediaRecorder_enableDeviceCallback %d", enabled);
+
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
+ if (mr == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ process_media_recorder_call(env, mr->enableAudioDeviceCallback(enabled),
+ "java/lang/RuntimeException", "enableDeviceCallback failed.");
+}
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] = {
@@ -689,6 +739,10 @@
{"native_setInputSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaRecorder_setInputSurface },
{"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaRecorder_native_getMetrics},
+
+ {"native_setInputDevice", "(I)Z", (void *)android_media_MediaRecorder_setInputDevice},
+ {"native_getRoutedDeviceId", "()I", (void *)android_media_MediaRecorder_getRoutedDeviceId},
+ {"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaRecorder_enableDeviceCallback},
};
// This function only registers the native methods, and is called from
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index fe2a939..4e8c72b 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -55,6 +55,7 @@
static jmethodID method_beginSendObject;
static jmethodID method_endSendObject;
+static jmethodID method_doScanDirectory;
static jmethodID method_getObjectList;
static jmethodID method_getNumObjects;
static jmethodID method_getSupportedPlaybackFormats;
@@ -119,6 +120,8 @@
MtpObjectFormat format,
bool succeeded);
+ virtual void doScanDirectory(const char* path);
+
virtual MtpObjectHandleList* getObjectList(MtpStorageID storageID,
MtpObjectFormat format,
MtpObjectHandle parent);
@@ -265,6 +268,16 @@
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
+void MyMtpDatabase::doScanDirectory(const char* path) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jstring pathStr = env->NewStringUTF(path);
+ env->CallVoidMethod(mDatabase, method_doScanDirectory, pathStr);
+
+ if (pathStr)
+ env->DeleteLocalRef(pathStr);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID,
MtpObjectFormat format,
MtpObjectHandle parent) {
@@ -1311,6 +1324,11 @@
ALOGE("Can't find endSendObject");
return -1;
}
+ method_doScanDirectory = env->GetMethodID(clazz, "doScanDirectory", "(Ljava/lang/String;)V");
+ if (method_doScanDirectory == NULL) {
+ ALOGE("Can't find doScanDirectory");
+ return -1;
+ }
method_getObjectList = env->GetMethodID(clazz, "getObjectList", "(III)[I");
if (method_getObjectList == NULL) {
ALOGE("Can't find getObjectList");
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index ab0da07..21410ea 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -24,7 +24,6 @@
#define USE_SHARED_MEM_BUFFER
#include <media/AudioTrack.h>
-#include <media/IMediaHTTPService.h>
#include <media/mediaplayer.h>
#include "SoundPool.h"
#include "SoundPoolThread.h"
diff --git a/media/mca/filterfw/Android.mk b/media/mca/filterfw/Android.mk
index 334f4e2..37f1e13 100644
--- a/media/mca/filterfw/Android.mk
+++ b/media/mca/filterfw/Android.mk
@@ -26,6 +26,8 @@
LOCAL_MODULE := libfilterfw
+LOCAL_CFLAGS := -Wall -Werror
+
LOCAL_MODULE_TAGS := optional
LOCAL_WHOLE_STATIC_LIBRARIES := libfilterfw_jni \
diff --git a/obex/javax/obex/ServerOperation.java b/obex/javax/obex/ServerOperation.java
index 56a675a..15ea367 100644
--- a/obex/javax/obex/ServerOperation.java
+++ b/obex/javax/obex/ServerOperation.java
@@ -195,7 +195,12 @@
if(!handleObexPacket(packet)) {
return;
}
- if (!mHasBody) {
+ /* Don't Pre-Send continue when Remote requested for SRM
+ * Let the Application confirm.
+ */
+ if (V) Log.v(TAG, "Get App confirmation if SRM ENABLED case: " + mSrmEnabled
+ + " not hasBody case: " + mHasBody);
+ if (!mHasBody && !mSrmEnabled) {
while ((!mGetOperation) && (!finalBitSet)) {
sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
if (mPrivateInput.available() > 0) {
@@ -204,8 +209,13 @@
}
}
}
-
- while ((!mGetOperation) && (!finalBitSet) && (mPrivateInput.available() == 0)) {
+ /* Don't Pre-Send continue when Remote requested for SRM
+ * Let the Application confirm.
+ */
+ if (V) Log.v(TAG, "Get App confirmation if SRM ENABLED case: " + mSrmEnabled
+ + " not finalPacket: " + finalBitSet + " not GETOp Case: " + mGetOperation);
+ while ((!mSrmEnabled) && (!mGetOperation) && (!finalBitSet)
+ && (mPrivateInput.available() == 0)) {
sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
if (mPrivateInput.available() > 0) {
break;
diff --git a/packages/BackupRestoreConfirmation/res/values-da/strings.xml b/packages/BackupRestoreConfirmation/res/values-da/strings.xml
index 3a74915..94872e2 100644
--- a/packages/BackupRestoreConfirmation/res/values-da/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-da/strings.xml
@@ -16,23 +16,23 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="backup_confirm_title" msgid="827563724209303345">"Fuld sikkerhedskopiering"</string>
+ <string name="backup_confirm_title" msgid="827563724209303345">"Fuld backup"</string>
<string name="restore_confirm_title" msgid="5469365809567486602">"Fuld genoprettelse"</string>
- <string name="backup_confirm_text" msgid="1878021282758896593">"Der er anmodet om en fuld sikkerhedskopiering af alle data til en tilsluttet stationær computer. Vil du tillade dette?\n\nHvis du ikke har anmodet om sikkerhedskopiering, skal du ikke tillade denne handling."</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"Der er anmodet om en fuld backup af alle data til en tilsluttet computer. Vil du tillade dette?\n\nHvis du ikke har anmodet om backup, skal du ikke tillade denne handling."</string>
<string name="allow_backup_button_label" msgid="4217228747769644068">"Sikkerhedskopiér mine data"</string>
<string name="deny_backup_button_label" msgid="6009119115581097708">"Undlad at sikkerhedskopiere"</string>
- <string name="restore_confirm_text" msgid="7499866728030461776">"Der er anmodet om en fuld sikkerhedskopiering af alle data til en tilsluttet stationær computer. Vil du tillade dette?\n\nHvis du ikke har anmodet om sikkerhedskopiering, skal du ikke tillade denne handling."</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"Der er anmodet om en fuld backup af alle data til en tilsluttet stationær computer. Vil du tillade dette?\n\nHvis du ikke har anmodet om backup, skal du ikke tillade denne handling."</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"Gendan mine data"</string>
<string name="deny_restore_button_label" msgid="1724367334453104378">"Gendan ikke"</string>
- <string name="current_password_text" msgid="8268189555578298067">"Indtast din aktuelle adgangskode til sikkerhedskopiering nedenfor:"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"Indtast din aktuelle adgangskode til backup nedenfor:"</string>
<string name="device_encryption_restore_text" msgid="1570864916855208992">"Indtast adgangskoden til kryptering for din enhed nedenfor."</string>
<string name="device_encryption_backup_text" msgid="5866590762672844664">"Indtast adgangskoden til kryptering for din enhed nedenfor. Denne bliver også brugt til at kryptere sikkerhedskopien af arkivet."</string>
- <string name="backup_enc_password_text" msgid="4981585714795233099">"Angiv en adgangskode, som skal bruges til kryptering af alle dine sikkerhedsdata. Hvis dette felt er tomt, bruges din aktuelle adgangskode til sikkerhedskopiering:"</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"Angiv en adgangskode, som skal bruges til kryptering af alle dine sikkerhedsdata. Hvis dette felt er tomt, bruges din aktuelle adgangskode til backup:"</string>
<string name="backup_enc_password_optional" msgid="1350137345907579306">"Hvis du ønsker at kryptere sikkerhedsdataene, skal du indtaste en adgangskode nedenfor:"</string>
<string name="backup_enc_password_required" msgid="7889652203371654149">"Eftersom din enhed er krypteret, skal du kryptere din backup. Indtast en adgangskode nedenfor:"</string>
<string name="restore_enc_password_text" msgid="6140898525580710823">"Hvis gendannelsesdataene er krypteret, skal du angive adgangskoden nedenfor:"</string>
- <string name="toast_backup_started" msgid="550354281452756121">"Sikkerhedskopiering begynder..."</string>
- <string name="toast_backup_ended" msgid="3818080769548726424">"Sikkerhedskopiering er færdig"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"Backup begynder..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"Backup er færdig"</string>
<string name="toast_restore_started" msgid="7881679218971277385">"Gendannelse begynder..."</string>
<string name="toast_restore_ended" msgid="1764041639199696132">"Gendannelse afsluttet"</string>
<string name="toast_timeout" msgid="5276598587087626877">"Handling fik timeout"</string>
diff --git a/packages/CompanionDeviceManager/res/drawable/dialog_background.xml b/packages/CompanionDeviceManager/res/drawable/dialog_background.xml
index af2c83f..a017f41 100644
--- a/packages/CompanionDeviceManager/res/drawable/dialog_background.xml
+++ b/packages/CompanionDeviceManager/res/drawable/dialog_background.xml
@@ -16,7 +16,7 @@
<inset xmlns:android="http://schemas.android.com/apk/res/android">
<shape android:shape="rectangle">
- <corners android:radius="2dp" />
+ <corners android:radius="?android:attr/dialogCornerRadius" />
<solid android:color="?android:attr/colorBackground" />
</shape>
</inset>
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 4a771eb..8b01aef 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -138,6 +138,7 @@
ret.packageName = pkg.packageName;
ret.splitNames = pkg.splitNames;
ret.versionCode = pkg.versionCode;
+ ret.versionCodeMajor = pkg.versionCodeMajor;
ret.baseRevisionCode = pkg.baseRevisionCode;
ret.splitRevisionCodes = pkg.splitRevisionCodes;
ret.installLocation = pkg.installLocation;
diff --git a/packages/EasterEgg/Android.mk b/packages/EasterEgg/Android.mk
index d4c1e70..a825581 100644
--- a/packages/EasterEgg/Android.mk
+++ b/packages/EasterEgg/Android.mk
@@ -2,17 +2,23 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
+
LOCAL_STATIC_JAVA_LIBRARIES := \
+ jsr305
+
+LOCAL_STATIC_ANDROID_LIBRARIES := \
android-support-v4 \
android-support-v13 \
android-support-dynamic-animation \
android-support-v7-recyclerview \
android-support-v7-preference \
android-support-v7-appcompat \
- android-support-v14-preference \
- jsr305
+ android-support-v14-preference
+
+LOCAL_USE_AAPT2 := true
LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := EasterEgg
LOCAL_CERTIFICATE := platform
diff --git a/packages/InputDevices/res/values-in/strings.xml b/packages/InputDevices/res/values-in/strings.xml
index 33b9ae3..f2409d4 100644
--- a/packages/InputDevices/res/values-in/strings.xml
+++ b/packages/InputDevices/res/values-in/strings.xml
@@ -25,7 +25,7 @@
<string name="keyboard_layout_swedish" msgid="732959109088479351">"Swedia"</string>
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finlandia"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Kroasia"</string>
- <string name="keyboard_layout_czech" msgid="1349256901452975343">"Cheska"</string>
+ <string name="keyboard_layout_czech" msgid="1349256901452975343">"Ceko"</string>
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estonia"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Hungaria"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandia"</string>
diff --git a/packages/Osu2/tests/Android.mk b/packages/Osu2/tests/Android.mk
index 4b6e0e6..afc743d 100644
--- a/packages/Osu2/tests/Android.mk
+++ b/packages/Osu2/tests/Android.mk
@@ -20,7 +20,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_JACK_FLAGS := --multi-dex native
diff --git a/packages/SettingsLib/Android.mk b/packages/SettingsLib/Android.mk
index 99f7f71..894a1ab 100644
--- a/packages/SettingsLib/Android.mk
+++ b/packages/SettingsLib/Android.mk
@@ -13,11 +13,11 @@
android-support-v7-recyclerview \
android-support-v7-preference \
android-support-v7-appcompat \
- android-support-v14-preference
+ android-support-v14-preference \
+ apptoolkit-lifecycle-runtime
LOCAL_SHARED_JAVA_LIBRARIES := \
- apptoolkit-lifecycle-common \
- apptoolkit-lifecycle-runtime
+ apptoolkit-lifecycle-common
LOCAL_STATIC_JAVA_LIBRARY := legacy-android-test
diff --git a/packages/SettingsLib/common.mk b/packages/SettingsLib/common.mk
index b9abde2..9d1c4ca 100644
--- a/packages/SettingsLib/common.mk
+++ b/packages/SettingsLib/common.mk
@@ -15,10 +15,16 @@
ifeq ($(LOCAL_USE_AAPT2),true)
LOCAL_STATIC_JAVA_LIBRARIES += \
- android-support-annotations
+ android-support-annotations \
+ apptoolkit-lifecycle-common
LOCAL_STATIC_ANDROID_LIBRARIES += \
android-support-v4 \
+ apptoolkit-lifecycle-runtime \
+ android-support-v7-recyclerview \
+ android-support-v7-preference \
+ android-support-v7-appcompat \
+ android-support-v14-preference \
SettingsLib
else
LOCAL_RESOURCE_DIR += $(call my-dir)/res
@@ -59,5 +65,7 @@
LOCAL_STATIC_JAVA_LIBRARIES += \
android-support-annotations \
android-support-v4 \
+ apptoolkit-lifecycle-runtime \
+ apptoolkit-lifecycle-common \
SettingsLib
endif
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 145060b..5652ad9 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Gaan wagwoord na en probeer weer"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Nie binne ontvangs nie"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Sal nie outomaties koppel nie"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Geen internettoegang nie"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Geen internettoegang nie"</string>
<string name="saved_network" msgid="4352716707126620811">"Gestoor deur <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Outomaties deur %1$s gekoppel"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Outomaties deur netwerkgraderingverskaffer gekoppel"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Gekoppel via %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Beskikbaar via %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Gekoppel, geen internet nie"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Gekoppel, geen internet nie"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Toegangspunt is tydelik vol"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Gekoppel via %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Beskikbaar via %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Aan SAP gekoppel"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nie gekoppel aan lêeroordragbediener nie"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Gekoppel aan invoertoestel"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Aan toestel gekoppel vir internettoegang"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Deel plaaslike internetverbinding met toestel"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Gebruik vir internettoegang"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Aan toestel gekoppel vir internettoegang"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Deel plaaslike internetverbinding met toestel"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Gebruik vir internettoegang"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Gebruik vir kaart"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Gebruik vir SIM-toegang"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Gebruik vir media-oudio"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Kon nie met <xliff:g id="DEVICE_NAME">%1$s</xliff:g> saambind nie weens \'n verkeerde PIN of wagwoordsleutel."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Kan nie met <xliff:g id="DEVICE_NAME">%1$s</xliff:g> kommunikeer nie."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Saambinding verwerp deur <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Rekenaar"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Kopstuk"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Foon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Prenttoestel"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Oorfoon"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Randinvoertoestel"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi af."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi is ontkoppel."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi een staaf."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth-oudio-LDAC-kodek: Speelgehalte"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Kies Bluetooth-oudio-LDAC-kodek:\nSpeelgehalte"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Stroming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS oor TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Indien dit geaktiveer is, probeer DNS oor TLS op poort 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Private DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Kies private DNS-modus"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Af"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunisties"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Gasheernaam van private DNS-verskaffer"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Voer gasheernaam van DNS-verskaffer in"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Wys opsies vir draadlose skermsertifisering"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Verhoog Wi-Fi-aantekeningvlak, wys per SSID RSSI in Wi‑Fi-kieser"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Wanneer dit geaktiveer is, sal Wi-Fi die dataverbinding aggressiewer na mobiel oordra wanneer die Wi-Fi-sein swak is"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Aktiveer 4x MSAA in OpenGL ES 2.0-programme"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Ontfout nie-reghoekige knipbedrywighede"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Profiel se GPU-lewering"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Aktiveer GPU-ontfoutlae"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Laat laai van GPU-ontfoutlae vir ontfoutapps toe"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Vensteranimasieskaal"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Oorganganimasieskaal"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Animator-tydsduurskaal"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 0abf21b..4aac238 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"የይለፍ ቃልን ይፈትሹ እና እንደገና ይሞክሩ"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"በክልል ውስጥ የለም"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"በራስ-ሰር አይገናኝም"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"ምንም የበይነመረብ መዳረሻ ያለም"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"ምንም የበይነመረብ መዳረሻ ያለም"</string>
<string name="saved_network" msgid="4352716707126620811">"የተቀመጠው በ<xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"በ%1$s በኩል በራስ-ሰር ተገናኝቷል"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"በአውታረ መረብ ደረጃ ሰጪ አቅራቢ በኩል በራስ-ሰር ተገናኝቷል"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"በ%1$s በኩል መገናኘት"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"በ%1$s በኩል የሚገኝ"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"ተገናኝቷል፣ ምንም በይነመረብ የለም"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ተገናኝቷል፣ ምንም በይነመረብ የለም"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"የመዳረሻ ነጥብ ለጊዜው ሞልቷል"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"በ%1$s በኩል ተገናኝቷል"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"በ%1$s በኩል የሚገኝ"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"ከSAP ጋር ተገናኝቷል"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ከፋይል ዝውውር አገልጋይ ጋር አልተያያዘም"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ወደ ግቤት መሣሪያ ተያይዟል"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"ለበይነመረብ ድረስ ወደ መሣሪያ ተያይዟል"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"የአካባቢያዊ በይነመረብ ተያያዥ ከመሣሪያ ጋር በማጋራት ላይ"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ለበይነ መረብ ድረስ ተጠቀም"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"ለበይነመረብ መዳረሻ ከመሣሪያ ጋር ተገናኝቷል"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"የአካባቢያዊ በይነመረብ ግንኙነት ለመሣሪያ በማጋራት ላይ"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"ለበይነ መረብ ድረስ ይጠቀሙ"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"ለካርታ ይጠቀሙ"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"ለሲም መዳረሻ መጠቀም"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"ለማህደረመረጃ ድምፅተጠቀም"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"ከ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ጋር ትክክለኛ ባልሆነ ፒን ወይም የይለፍቁልፍ ምክንያት ማጣመር አልተቻለም::"</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"ከ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ጋር ግንኙነት መመስረት አልተቻለም።"</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"ማጣመር በ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ተገፍቷል።"</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"ኮምፒዩተር"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"ጆሮ ማዳመጫ"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"ስልክ"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"ምስል መስራት"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"የጆሮ ማዳመጫ"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"የግቤት መለዋወጫ"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"ብሉቱዝ"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi ጠፍቷል።"</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"የWifi ግንኙነት ተቋርጧል።"</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"አንድ የWiFi አሞሌ።"</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"የብሉቱዝ ኦዲዮ LDAC ኮዴክ ይምረጡ፦ የመልሶ ማጫወት ጥራት"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"የብሉቱዝ ኦዲዮ LDAC ኮዴክ ይምረጡ፦\nየመልሶ ማጫወት ጥራት"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"ዥረት፦ <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS በTLS ላይ"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"ከነቃ በወደብ 853 ላይ DNS በTLS ላይ ይሞክሩት።"</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"የግል ዲኤንኤስ"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"የግል ዲኤንኤስ ሁነታ ይምረጡ"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"ጠፍቷል"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"አድርባይ"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"የግል ዲኤንኤስ አቅራቢ አስተናጋጅ ስም"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"የዲኤንኤስ አቅራቢ አስተናጋጅ ስም ያስገቡ"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"የገመድ አልባ ማሳያ እውቅና ማረጋገጫ አማራጮችን አሳይ"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"የWi‑Fi ምዝግብ ማስታወሻ አያያዝ ደረጃ ጨምር፣ በWi‑Fi መምረጫ ውስጥ በአንድ SSID RSSI አሳይ"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"ሲነቃ የWi‑Fi ምልክት ዝቅተኛ ሲሆን Wi‑Fi የውሂብ ግንኙነት ለሞባይል ማስረከብ ላይ ይበልጥ አስገዳጅ ይሆናል"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"4x MSAA በ OpenGL ES 2.0 መተግበሪያዎች ውስጥ ያንቁ"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"አራት ማእዘን ያልሆኑ የቅንጥብ ክዋኔዎችን ስህተት አርም"</string>
<string name="track_frame_time" msgid="6146354853663863443">"የGPU ምላሽ መስጠት መዝግብ"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"የጂፒዩ ስህተት ማረሚያ ንብርብሮችን ያንቁ"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"ለስህተት ማረሚያ መተግበሪያዎች የጂፒዩ ንብርብሮችን መስቀልን ፍቀድ"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"የዊንዶው እነማ ልኬት ለውጥ"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"የእነማ ልኬት ለውጥ ሽግግር"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"እነማ አድራጊ ቆይታ መለኪያ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index e0a979d..90cc221 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"يُرجى التحقق من كلمة المرور وإعادة المحاولة"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"ليست في النطاق"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"لن يتم الاتصال تلقائيًا"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"لا يتوفر اتصال بالإنترنت"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"لا يتوفّر اتصال بالإنترنت"</string>
<string name="saved_network" msgid="4352716707126620811">"تم الحفظ بواسطة <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"تم الاتصال تلقائيًا عبر %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"تم الاتصال تلقائيًا عبر مقدم خدمة تقييم الشبكة"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"تم الاتصال عبر %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"متوفرة عبر %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"متصلة، ولا يتوفر إنترنت"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"متصلة ولكن بلا إنترنت"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"نقطة الدخول ممتلئة مؤقتًا"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"تم الاتصال عبر %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"متوفرة عبر %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"تم الاتصال بـ SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"غير متصل بخادم نقل الملفات"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"متصل بجهاز الإدخال"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"متصل بالجهاز لدخول الإنترنت"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"مشاركة الاتصال المحلي بالإنترنت مع الجهاز"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"الاستخدام للدخول على الإنترنت"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"متصل بالجهاز للدخول إلى الإنترنت"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"تتم مشاركة اتصال الإنترنت المحلي مع الجهاز"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"الاستخدام للاتصال بالإنترنت"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"استخدام لملف تعريف الدخول إلى الرسائل"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"الاستخدام للوصول إلى شريحة SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"الاستخدام للإعدادات الصوتية للوسائط"</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"تمكين 4x MSAA في تطبيقات OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"تصحيح أخطاء عمليات القصاصات غير المستطيلة"</string>
<string name="track_frame_time" msgid="6146354853663863443">"رسم مخطط لعرض GPU"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"تفعيل طبقات تصحيح أخطاء GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"السماح بتحميل طبقات تصحيح أخطاء GPU لتطبيقات تصحيح الأخطاء"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"حجم الرسوم المتحركة للنافذة"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"حجم الرسوم المتحركة للنقل"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"طول مدة الرسوم المتحركة"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 0ae9025..1053079 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Parolu yoxlayın və yenidən cəhd edin"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Diapazonda deyil"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Avtomatik qoşulmayacaq"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"İnternet girişi yoxdur"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"İnternet girişi yoxdur"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tərəfindən saxlandı"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s üzərindən avtomatik qoşuldu"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Avtomatik olaraq şəbəkə reytinq provayderi ilə qoşuludur"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s vasitəsilə qoşuludur"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s vasitəsilə əlçatandır"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Qoşuludur, internet yoxdur"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Qoşuludur, internet yoxdur"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Giriş nöqtəsi müvəqqəti olaraq doludur"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s ilə qoşuludur"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s vasitəsilə əlçatandır"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP(es-ey-pi)\'yə qoşuludur"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Fayl transfer serverinə qoşulmayıb"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Daxiletmə cihazına qoşuldu"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"İnternet girişi üçün cihaza birləşdi"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Lokal internet bağlantısı cihazla paylaşılır"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"İnternet girişi üçün istifadə edin"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"İnternet bağlantısı üçün cihaza qoşuldu"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Lokal internet bağlantısı cihaz ilə paylaşılır"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"İnternet girişi üçün istifadə edin"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Xəritə üçün istifadə et"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM girişi üçün istifadə edin"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Media audio istifadə edin"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Yanlış PIN və ya parola görə <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ilə cütləşmək alınmadı."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ilə ünsiyyət qurula bilmir."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Cütləşdirmə <xliff:g id="DEVICE_NAME">%1$s</xliff:g> tərəfindən rədd edildi."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Kompüter"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Qulaqlıq"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Şəkilləndirmə"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Qulaqlıq"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Daxiletmə periferiki"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi sönülüdür."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi bağlantı kəsildi."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wifi bir xətdir."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth Audio LDAC Kodeki:Oxutma Keyfiyyəti"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Bluetooth Audio LDAC Kodek:\nOxutma Keyfiyyəti Seçin"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Canlı yayım: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"TLS ilə DNS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Aktiv edilərsə, 853 nömrəli portda TLS ilə DNS-i sınayın."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Şəxsi DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Şəxsi DNS Rejimini Seçin"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Deaktiv"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Geniş imkanlar"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Şəxsi DNS provayderinin host adı"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS provayderinin host adını daxil edin"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Simsiz displey sertifikatlaşması üçün seçimləri göstərir"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi giriş səviyyəsini qaldırın, Wi‑Fi seçəndə hər SSID RSSI üzrə göstərin"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Aktiv edildikdə, Wi-Fi siqnalı zəif olan zaman, data bağlantısını mobilə ötürərəkən Wi-Fi daha aqressiv olacaq"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 tətbiqlərində 4x MSAA aktiv et"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Qeyri-düzbucaqlı klip əməliyyatlarını debaq edin"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Profil GPU render"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU debaq təbəqələrini aktiv edin"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"GPU debaq təbəqələrinin yüklənməsinə icazə verin"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Pəncərə animasiya miqyası"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Animasiya keçid miqyası"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Animator müddət şkalası"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index ef4e48e..5239f5a 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Proverite lozinku i probajte ponovo"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u opsegu"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Automatsko povezivanje nije uspelo"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Nema pristupa internetu"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Nema pristupa internetu"</string>
<string name="saved_network" msgid="4352716707126620811">"Sačuvao/la je <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatski povezano preko %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatski povezano preko dobavljača ocene mreže"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Veza je uspostavljena preko pristupne tačke %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Dostupna je preko pristupne tačke %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Veza je uspostavljena, nema interneta"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Veza je uspostavljena, nema interneta"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Pristupna tačka je privremeno zauzeta"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Povezano preko %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Dostupno preko %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Veza sa tačkom pristupa uslugama je uspostavljena"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nije povezano sa serverom za prenos datoteka"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Povezan sa ulaznim uređajem"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Povez. sa uređ. radi pristupa Internetu"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Lokalna internet veza se deli sa uređajem"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Koristi za pristup Internetu"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Povezano je sa uređajem radi pristupa internetu"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Lokalna internet veza se deli sa uređajem"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Koristi za pristup internetu"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Koristi se za mapu"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Koristi za pristup SIM kartici"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Korišćenje za zvuk medija"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Uparivanje sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> nije moguće zbog netačnog PIN-a ili pristupnog koda."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Nije moguće komunicirati sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> je odbio/la uparivanje"</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Računar"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Naglavne slušalice"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Pozovi"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Obrada slika"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Slušalice"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Periferni uređaj za unos"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi je isključen."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi veza je prekinuta."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi signal ima jednu crtu."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth audio kodek LDAC: kvalitet reprodukcije"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Izaberite Bluetooth audio kodek LDAC:\nkvalitet reprodukcije"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Strimovanje: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS preko TLS-a"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Ako je omogućeno, probajte DNS preko TLS-a na portu 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privatni DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Izaberite režim privatnog DNS-a"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Isključeno"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistički"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Ime hosta dobavljača usluge privatnog DNS-a"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Unesite ime hosta dobavljača usluge DNS-a"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Prikaz opcija za sertifikaciju bežičnog ekrana"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećava nivo evidentiranja za Wi‑Fi. Prikaz po SSID RSSI-u u biraču Wi‑Fi mreže"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Kad se omogući, Wi‑Fi će biti agresivniji pri prebacivanju mreže za prenos podataka na mobilnu ako je Wi‑Fi signal slab"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Omogući 4x MSAA u OpenGL ES 2.0 aplikacijama"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Otkloni greške u vezi sa radnjama za isecanje oblasti koje nisu pravougaonog oblika"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Prikaži profil pomoću GPU"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Omogući slojeve za otklanjanje grešaka GPU-a"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Omogući učitavanje sloj. za otk. greš. GPU-a u apl. za otk. greš."</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Razmera animacije prozora"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Razmera animacije prelaza"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Animatorova razmera trajanja"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 3efe3bf..c6aa478 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Праверце пароль і паўтарыце спробу"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Не ў зоне дасягальнасці"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Не будзе аўтаматычна падключацца"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Няма доступу да інтэрнэту"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Няма доступу да інтэрнэту"</string>
<string name="saved_network" msgid="4352716707126620811">"Хто захаваў: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Аўтаматычна падключана праз %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Аўтаматычна падключана праз пастаўшчыка паслугі ацэнкі сеткі"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Падлучана праз %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Даступна праз %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Падлучана, няма інтэрнэту"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Падключана, без доступу да інтэрнэту"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Пункт доступу часова заняты"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Падлучана праз %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Даступна праз %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Падключана да SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Няма падключэння да серверу перадачы файлаў"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Падключана да прылады ўводу"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Прылада для дост. ў Iнт."</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Сумеснае выкарыстанне лакальнага падключэння да інтэрнэту з прыладай"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Выкарыстоўвайце для доступу ў Інтэрнэт"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Падключэнне да прылады для доступу ў інтэрнэт"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Абагульванне лакальнага падключэння да інтэрнэту з прыладай"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Выкарыстоўваць для доступу ў інтэрнэт"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Выкарыстоўваць для карты"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Выкарыстоўваць для доступу да SIM-карты"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Выкарыстоўваць для аўдыё-медыя"</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Уключыць 4x MSAA у прыкладаннях з OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Адладка аперацый непрамавугольнага кліпа"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Профіль рэндэрынгу GPU"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Уключыць слаі адладкі GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Дазв. загр. слаёў адладкі GPU для праграм адладкі"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Маштаб анімацыі акна"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Маштаб перадачы анімацыі"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Шкала працягласці анiматара"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index d8b650a..c932c83 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Проверете паролата и опитайте отново"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Извън обхват"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Няма да се свърже автоматично"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Няма достъп до интернет"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Няма достъп до интернет"</string>
<string name="saved_network" msgid="4352716707126620811">"Запазено от <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Автоматично е установена връзка чрез %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Автоматично е установена връзка чрез доставчик на услуги за оценяване на мрежите"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Установена е връзка през „%1$s“"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Мрежата е достъпна през „%1$s“"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Установена е връзка – няма достъп до интернет"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Установена е връзка – няма достъп до интернет"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Точката за достъп временно е пълна"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Установена е връзка през %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Мрежата е достъпна през %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Установена е връзка със SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Няма връзка със сървър за трансфер на файлове"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Има връзка с устройството за въвеждане"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Има връзка с у-во за достъп до интернет"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Лок. връзка с интернет се споделя с у-вото"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Използване за достъп до интернет"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Има връзка с у-во за достъп до интернет"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Лок. връзка с интернет се споделя с у-вото"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Използване за достъп до интернет"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Да се използва за MAP"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Използване за достъп до SIM картата"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Употреба за медийно аудио"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Не можа да се сдвои с/ъс <xliff:g id="DEVICE_NAME">%1$s</xliff:g> поради неправилен ПИН или код за достъп."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Не може да се свърже с/ъс <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Сдвояването е отхвърлено от <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Компютър"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Слушалки"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Телефон"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Изображения"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Слушалки"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Периферен вход"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi е изключен."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Няма връзка с Wi-Fi."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi е с една чертичка."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Кодек за звука през Bluetooth с технологията LDAC: Качество на възпроизвеждане"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Изберете кодек за звука през Bluetooth с технологията LDAC:\nКачество на възпроизвеждане"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Поточно предаване: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS през TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Ако опцията е активирана, изпробвайте DNS през TLS на порт 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Частен DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Изберете режим на частния DNS"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Изкл."</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"При възможност"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Име на хоста на доставчика на частния DNS"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Въведете името на хоста на DNS доставчика"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показване на опциите за сертифициране на безжичния дисплей"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"По-подробно регистр. на Wi‑Fi – данни за RSSI на SSID в инстр. за избор на Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"При активиране предаването на връзката за данни от Wi-Fi към мобилната мрежа ще е по-агресивно, когато сигналът за Wi-Fi е слаб"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Активиране на 4x MSAA в прилож. с OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Отстр. на грешки при неправоъг. изрязване"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Профилиране на GPU"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Слоеве за отстр. на грешки в ГП: Актив."</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Разреш. на зарежд. на слоевете за отстр. на грешки в ГП за съотв. прилож."</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Скала на аним.: Прозорец"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Скала на преходната анимация"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Скала за Animator"</string>
diff --git a/packages/SettingsLib/res/values-bs/arrays.xml b/packages/SettingsLib/res/values-bs/arrays.xml
index c274d4c..af04a04 100644
--- a/packages/SettingsLib/res/values-bs/arrays.xml
+++ b/packages/SettingsLib/res/values-bs/arrays.xml
@@ -231,7 +231,7 @@
</string-array>
<string-array name="debug_hw_overdraw_entries">
<item msgid="8190572633763871652">"Isključeno"</item>
- <item msgid="7688197031296835369">"Prikaži overdraw područja"</item>
+ <item msgid="7688197031296835369">"Prikaži područja preklapanja"</item>
<item msgid="2290859360633824369">"Prikaži područja za Deuteranomaly"</item>
</string-array>
<string-array name="debug_hw_renderer_entries">
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index ca610f7..ed0958c 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Provjerite lozinku i pokušajte ponovo"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u dometu"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Neće se automatski povezati"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Nema pristupa internetu"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Nema pristupa internetu"</string>
<string name="saved_network" msgid="4352716707126620811">"Sačuvano: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatski povezano koristeći %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatski povezano putem ocjenjivača mreže"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Povezani preko %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Dostupan preko %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Povezano. Nema interneta"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Povezano, nema interneta"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Pristupna tačka je privremeno puna"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Povezana koristeći %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Dostupna koristeći %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Povezan na SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nije povezan na server za prijenos podataka"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Spojen na ulazni uređaj"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Pov. na ur. za pris. int."</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Dij. lok. int. veze s ur."</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Koristi za pristup internetu"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Povezano na uređaj za pristup internetu"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Dijeljenje lokalne internetske veze s uređajem"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Koristi za pristup internetu"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Koristi za mapu"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Koristi za pristup SIM-u"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Koristi za zvuk medija"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nije se moguće upariti s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> zbog pogrešnog PIN-a ili pristupnog koda."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Ne može komunicirati sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Uređaj <xliff:g id="DEVICE_NAME">%1$s</xliff:g> je odbio uparivanje."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Računar"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Slušalice s mikrofonom"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Snimanje"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Slušalice"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Ulazni periferni uređaj"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi isključen."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi nije povezan."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi jedna crtica."</string>
@@ -209,12 +216,16 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth Audio LDAC kodek: Kvalitet reprodukcije"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Odaberite Bluetooth Audio LDAC kodek:\nKvalitet reprodukcije"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Prijenos: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS preko TLS-a"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Ako je opcija omogućena, pokušaj DNS preko TLS-a na priključku 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privatni DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Odaberite način rada privatnog DNS-a"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Isključeno"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunistički"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Naziv host računara privatnog DNS-a"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Unesite naziv host računara pružaoca DNS-a"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaži opcije za certifikaciju Bežičnog prikaza"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećajte nivo Wi-Fi zapisivanja, pokazati po SSID RSSI Wi-Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Kada je omogućeno, Wi-Fi veza će u slučaju slabog signala agresivnije predavati vezu za prijenos podataka na mobilnu vezu"</string>
- <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Dozvoli/Zabrani Wi-Fi lutajuće skeniranje na osnovu količine podatkovnog prometa prisutnog na sučelju"</string>
+ <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Dozvoli/Zabrani Wi-Fi lutajuće skeniranje na osnovu količine podatkovnog prometa prisutnog na interfejsu"</string>
<string name="select_logd_size_title" msgid="7433137108348553508">"Veličine bafera za zapisnik"</string>
<string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Odaberite veličine za Logger prema međumemoriji evidencije"</string>
<string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"Želite li izbrisati trajnu pohranu zapisivača?"</string>
@@ -267,7 +278,7 @@
<string name="show_hw_screen_updates_summary" msgid="1115593565980196197">"Prikazi uz treptanje unutar prozora kada se crta koristeći GPU"</string>
<string name="show_hw_layers_updates" msgid="5645728765605699821">"Prikaži dodatne informacije za ažuriranja za hardver"</string>
<string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Trepći hardverske slojeve zeleno kada se ažuriraju"</string>
- <string name="debug_hw_overdraw" msgid="2968692419951565417">"Otkl. GPU overdraw greške"</string>
+ <string name="debug_hw_overdraw" msgid="2968692419951565417">"Otkl. greške GPU preklap."</string>
<string name="debug_hw_renderer" msgid="7568529019431785816">"Postavite GPU renderer"</string>
<string name="disable_overlays" msgid="2074488440505934665">"Onemog. HW preklapanja"</string>
<string name="disable_overlays_summary" msgid="3578941133710758592">"Uvijek koristi GPU za kompoziciju ekrana"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Omogući 4x MSAA u OpenGL ES 2.0 aplikacijama"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Ispravi pogreške na nepravougaonim operacijama isecanja"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Profil GPU iscrtavanja"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Omogući slojeve za otklanjanje grešaka na GPU-u"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Omogući učitavanje slojeva za otklanjanje grešaka na GPU-u za aplikacije za otklanjanje grešaka"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Skala animacije prozora"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Skaliranje animacije prijelaza"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Skala trajanja animatora"</string>
diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml
index b163642..3cda6ab 100644
--- a/packages/SettingsLib/res/values-ca/arrays.xml
+++ b/packages/SettingsLib/res/values-ca/arrays.xml
@@ -231,7 +231,7 @@
</string-array>
<string-array name="debug_hw_overdraw_entries">
<item msgid="8190572633763871652">"Desactiva"</item>
- <item msgid="7688197031296835369">"Mostra les àrees superposades"</item>
+ <item msgid="7688197031296835369">"Mostra les àrees sobredibuixades"</item>
<item msgid="2290859360633824369">"Mostra les àrees amb deuteranomalia"</item>
</string-array>
<string-array name="debug_hw_renderer_entries">
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 9d86055..e65adcd 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -33,15 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Comprova la contrasenya i torna-ho a provar"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Fora de l\'abast"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"No es connectarà automàticament"</string>
- <!-- no translation found for wifi_no_internet (4663834955626848401) -->
- <skip />
+ <string name="wifi_no_internet" msgid="4663834955626848401">"No hi ha accés a Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Desat per <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Connectada automàticament a través de: %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Connectada automàticament a través d\'un proveïdor de valoració de xarxes"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Connectada mitjançant %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Disponible mitjançant %1$s"</string>
- <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connectada, sense Internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"El punt d\'accés està temporalment ple"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Connectat mitjançant %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Disponible mitjançant %1$s"</string>
@@ -86,8 +84,7 @@
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Connectat a dispositiu d\'entrada"</string>
<string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Connectat per accedir a Internet"</string>
<string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Compartint la connexió local amb el dispositiu"</string>
- <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
- <skip />
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Utilitza\'l per a l\'accés a Internet"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Utilitza per al mapa"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Utilitza per a l\'accés a la SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Utilitza per a l\'àudio del mitjà"</string>
@@ -281,7 +278,7 @@
<string name="show_hw_screen_updates_summary" msgid="1115593565980196197">"Actualitza visualitzacions de finestres creades amb GPU"</string>
<string name="show_hw_layers_updates" msgid="5645728765605699821">"Mostra actualitzacions capes"</string>
<string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Il·lumina capes de maquinari en verd en actualitzar-se"</string>
- <string name="debug_hw_overdraw" msgid="2968692419951565417">"Depura superposició de GPU"</string>
+ <string name="debug_hw_overdraw" msgid="2968692419951565417">"Depura sobredibuix de GPU"</string>
<string name="debug_hw_renderer" msgid="7568529019431785816">"Configura renderitzador GPU"</string>
<string name="disable_overlays" msgid="2074488440505934665">"Desactiva superposicions HW"</string>
<string name="disable_overlays_summary" msgid="3578941133710758592">"Utilitza sempre GPU per combinar pantalles"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 60bbbf3..771a32d 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Zkontrolujte heslo a zkuste to znovu"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Mimo dosah"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Připojení nebude automaticky navázáno"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Nebyl zjištěn žádný přístup k internetu"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Nebyl zjištěn žádný přístup k internetu"</string>
<string name="saved_network" msgid="4352716707126620811">"Uloženo uživatelem <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Automaticky připojeno přes poskytovatele %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automaticky připojeno přes poskytovatele hodnocení sítí"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Připojeno prostřednictvím %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Dostupné prostřednictvím %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Připojeno, není k dispozici internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Připojeno, není k dispozici internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Přístupový bod je dočasně zaplněn"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Připojeno prostřednictvím %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Dostupné prostřednictvím %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Připojeno k SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nepřipojeno k serveru pro přenos souborů"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Připojeno ke vstupnímu zařízení"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Připojeno k zařízení za účelem přístupu k internetu"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Místní internetové připojení je sdíleno se zařízením"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Použít pro přístup k internetu"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Připojeno k zařízení za účelem přístupu k internetu"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Místní internetové připojení je sdíleno se zařízením"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Použít pro přístup k internetu"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Použít pro mapu"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Používat pro přístup k SIM kartě"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Umožňuje připojení zvukového média"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nelze párovat se zařízením <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Kód PIN nebo přístupový klíč je nesprávný."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Se zařízením <xliff:g id="DEVICE_NAME">%1$s</xliff:g> nelze navázat komunikaci."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Párování odmítnuto zařízením <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Počítač"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Náhlavní souprava"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Zobrazovací zařízení"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Sluchátka"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Periferní vstupní zařízení"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Síť Wi-Fi je vypnuta."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Síť Wi-Fi je odpojena."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi – jedna čárka."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Kodek Bluetooth Audio LDAC: Kvalita přehrávání"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Vyberte kodek Bluetooth Audio LDAC:\nKvalita přehrávání"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streamování: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS přes TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Pokud tuto možnost aktivujete, zařízení se bude připojovat k serverům DNS pomocí protokolu TLS na portu 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Soukromé DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Vyberte soukromý režim DNS"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Vypnuto"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Příležitostné"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Název hostitele poskytovatele soukromého DNS"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Zadejte název hostitele poskytovatele DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Zobrazit možnosti certifikace bezdrátového displeje"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Zvýšit úroveň protokolování Wi‑Fi zobrazenou v SSID a RSSI při výběru sítě Wi‑Fi."</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Pokud je tato možnost zapnuta, bude síť Wi-Fi při předávání datového připojení mobilní síti při slabém signálu Wi-Fi agresivnější."</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Povolit 4x MSAA v aplikacích OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Ladit operace s neobdélníkovými výstřižky"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Profil – vykreslování GPU"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Povolit vrstvy ladění GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Povolit načítání vrstev ladění GPU pro ladicí aplikace"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Měřítko animace okna"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Měřítko animace přeměny"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Měřítko délky animace"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 089c43c..c3cfdff 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Tjek adgangskoden, og prøv igen"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Ikke inden for rækkevidde"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Der oprettes ikke automatisk forbindelse"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Ingen internetadgang"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Ingen internetadgang"</string>
<string name="saved_network" msgid="4352716707126620811">"Gemt af <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatisk tilsluttet via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatisk forbundet via udbyder af netværksvurdering"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Tilsluttet via %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Tilgængelig via %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Tilsluttet – intet internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Tilsluttet – intet internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Adgangspunktet er midlertidigt fuldt"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Tilsluttet via %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Tilgængelig via %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Sluttet til SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Ikke forbundet til filoverførselsserver"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Forbundet til inputenhed"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Tilsluttet enhed/internet"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Deler lokal internetforbindelse med enhed"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Brug til internetadgang"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Tilsluttet enhed for at få internetadgang"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Deler lokal internetforbindelse med enhed"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Brug til internetadgang"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Brug til kort"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Brug til SIM-adgang"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Brug til medielyd"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Der kunne ikke parres med <xliff:g id="DEVICE_NAME">%1$s</xliff:g> på grund af en forkert pinkode eller adgangsnøgle."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Der kan ikke kommunikeres med <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Parring afvist af <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Computer"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Headset"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Billede"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Hovedtelefoner"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Eksterne inputenheder"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi er slået fra."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi er afbrudt."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi har én bjælke."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"LDAC-codec for Bluetooth-lyd: Afspilningskvalitet"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Vælg LDAC-codec for Bluetooth-lyd:\nAfspilningskvalitet"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streamer: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS via TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Prøv DNS via TLS (hvis muligheden er aktiveret) på port 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privat DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Vælg privat DNS-tilstand"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Fra"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistisk"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Hostname for privat DNS-udbyder"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Angiv hostname for DNS-udbyder"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Vis valgmuligheder for certificering af trådløs skærm"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Øg mængden af Wi‑Fi-logføring. Vis opdelt efter SSID RSSI i Wi‑Fi-vælgeren"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Når dette er aktiveret, gennemtvinges en overdragelse af dataforbindelsen fra Wi-Fi til mobilnetværk, når Wi-Fi-signalet er svagt"</string>
@@ -229,7 +240,7 @@
<string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Hold altid mobildata aktiveret, selv når Wi-Fi er aktiveret (for at skifte hurtigt mellem netværk)."</string>
<string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Brug hardwareacceleration ved netdeling, hvis det er muligt"</string>
<string name="adb_warning_title" msgid="6234463310896563253">"Vil du tillade USB-fejlretning?"</string>
- <string name="adb_warning_message" msgid="7316799925425402244">"USB-fejlretning er kun beregnet til udvikling og kan bruges til at kopiere data mellem din computer og enheden, installere apps på enheden uden meddelelser og læse logdata."</string>
+ <string name="adb_warning_message" msgid="7316799925425402244">"USB-fejlretning er kun beregnet til udvikling og kan bruges til at kopiere data mellem din computer og enheden, installere apps på enheden uden underretning og læse logdata."</string>
<string name="adb_keys_warning_message" msgid="5659849457135841625">"Vil du ophæve adgangen til USB-fejlfinding for alle computere, du tidligere har godkendt?"</string>
<string name="dev_settings_warning_title" msgid="7244607768088540165">"Vil du tillade udviklingsindstillinger?"</string>
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Disse indstillinger er kun beregnet til brug i forbindelse med udvikling. De kan forårsage, at din enhed og dens applikationer går ned eller ikke fungerer korrekt."</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Aktivér 4x MSAA i apps med OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Fejlfind på ikke-rektangulære klippehandlinger"</string>
<string name="track_frame_time" msgid="6146354853663863443">"GPU-profilgengivelse"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Aktivér fejlretningslag for grafikprocessor"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Tillad, at fejlretningslag indlæses for grafikprocessor i apps til fejlretning"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Animationsskala for vindue"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Overgangsanimationsskala"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Animatorvarighedsskala"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 2635e66..c52c7ca 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Prüfe das Passwort und versuch es noch einmal"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Nicht in Reichweite"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Kein automatischer Verbindungsaufbau"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Kein Internetzugriff"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Kein Internetzugriff"</string>
<string name="saved_network" msgid="4352716707126620811">"Gespeichert von <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatisch über %1$s verbunden"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatisch über Anbieter von Netzwerkbewertungen verbunden"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Über %1$s verbunden"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Verfügbar über %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Verbunden, kein Internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Verbunden, kein Internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Zugangspunkt vorübergehend voll belegt"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Über %1$s verbunden"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Verfügbar über %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Mit SAP verbunden"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nicht mit Dateiübertragungsserver verbunden"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Mit einem Eingabegerät verbunden"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Für Internetzugriff an Gerät angeschlossen"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Lokale Internetverbindung für Gerät freigeben"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Für Internetzugriff verwenden"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Für Internetzugriff mit Gerät verbunden"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Lokale Internetverbindung für Gerät freigegeben"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Für Internetzugriff verwenden"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Für Karte verwenden"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Für SIM-Zugriff verwenden"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Für Audiosystem von Medien verwenden"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Kopplung mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> war nicht möglich, weil die eingegebene PIN oder der Zugangscode falsch ist."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Kommunikation mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ist nicht möglich."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Verbindung wurde von <xliff:g id="DEVICE_NAME">%1$s</xliff:g> abgelehnt."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Computer"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Headset"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Smartphone"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Bildverarbeitung"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Kopfhörer"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Eingabeperipherie"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"WLAN: aus"</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"WLAN getrennt"</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"WLAN: ein Balken"</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth-Audio-LDAC-Codec: Wiedergabequalität"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Bluetooth-Audio-LDAC-Codec auswählen:\nWiedergabequalität"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS-over-TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Wenn diese Option aktiviert ist, versuche für Port 853 DNS-over-TLS anzuwenden."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privates DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Privaten DNS-Modus auswählen"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Aus"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistisch"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Hostname des privaten DNS-Anbieters"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Hostname des DNS-Anbieters eingeben"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Optionen zur Zertifizierung für kabellose Übertragung anzeigen"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Level für WLAN-Protokollierung erhöhen, in WiFi Picker pro SSID-RSSI anzeigen"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Wenn diese Option aktiviert ist, ist das WLAN bei schwachem Signal bei der Übergabe der Datenverbindung an den Mobilfunk aggressiver"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"4x MSAA in OpenGL ES 2.0-Apps aktivieren"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Nicht rechteckige Clip-Operationen debuggen"</string>
<string name="track_frame_time" msgid="6146354853663863443">"GPU-Rendering für Profil"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU-Debugging-Ebene aktivieren"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Laden von GPU-Debugging-Ebene für Debugging-Apps erlauben"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Maßstab Fensteranimation"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Maßstab Übergangsanimation"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Maßstab für Animatorzeit"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index b6b1bde..9552c73 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Ελέγξτε τον κωδικό πρόσβασης και δοκιμάστε ξανά"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Εκτός εμβέλειας"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Δεν θα συνδεθεί αυτόματα"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Δεν υπάρχει πρόσβαση στο διαδίκτυο"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Δεν υπάρχει πρόσβαση στο διαδίκτυο"</string>
<string name="saved_network" msgid="4352716707126620811">"Αποθηκεύτηκε από <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Συνδέθηκε αυτόματα μέσω %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Συνδέθηκε αυτόματα μέσω παρόχου αξιολόγησης δικτύου"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Συνδέθηκε μέσω %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Διαθέσιμο μέσω %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Συνδέθηκε, χωρίς διαδίκτυο"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Συνδέθηκε, χωρίς σύνδεση στο διαδίκτυο"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Το σημείο πρόσβασης είναι προσωρινά πλήρες"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Συνδέθηκε μέσω %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Διαθέσιμο μέσω %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Συνδέθηκε σε SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Δεν έχει συνδεθεί σε διακομιστή μεταφοράς αρχείων"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Συνδέθηκε σε συσκευή εισόδου"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Συνδέθηκε με συσκευή με πρόσβ. στο Διαδ."</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Κοιν. χρ. σύνδ. στο Διαδ. με συσκευή"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Χρήση για την πρόσβαση στο Διαδίκτυο"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Συνδέθηκε με συσκευή με πρόσβαση στο διαδίκτυο"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Κοινόχρηστη χρήση σύνδεσης στο διαδίκτυο με συσκευή"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Χρήση για πρόσβαση στο διαδίκτυο"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Χρήση για χάρτη"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Χρήση για πρόσβαση στη SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Χρήση για ήχο πολυμέσων"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Δεν ήταν δυνατή η σύζευξη με τη συσκευή <xliff:g id="DEVICE_NAME">%1$s</xliff:g> λόγω εσφαλμένου αριθμού PIN ή κλειδιού πρόσβασης."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Δεν είναι δυνατή η σύνδεση με τη συσκευή <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Η ζεύξη απορρίφθηκε από τη συσκευή <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Υπολογιστής"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Ακουστικό"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Τηλέφωνο"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Απεικόνιση"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Ακουστικά"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Περιφερειακό εισόδου"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi ανενεργό."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Το Wi-Fi έχει αποσυνδεθεί."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Μία γραμμή Wi-Fi."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Κωδικοποιητής LDAC ήχου Bluetooth: Ποιότητα αναπαραγωγής"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Επιλογή κωδικοποιητή LDAC ήχου Bluetooth:\nΠοιότητα αναπαραγωγής"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Ροή: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS μέσω TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Εάν ενεργοποιηθεί, γίνεται προσπάθεια DNS μέσω TLS στη θύρα 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Ιδιωτικό DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Επιλέξτε τη λειτουργία ιδιωτικού DNS"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Ανενεργή"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Καιροσκοπική"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Όνομα κεντρικού υπολογιστή παρόχου DNS"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Εισαγάγετε το όνομα κεντρικού υπολογιστή του παρόχου DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Εμφάνιση επιλογών για πιστοποίηση ασύρματης οθόνης"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Αύξηση επιπέδου καταγ. Wi-Fi, εμφάνιση ανά SSID RSSI στο εργαλείο επιλογής Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Όταν είναι ενεργό, το Wi-Fi θα μεταβιβάζει πιο επιθετικά τη σύνδ.δεδομένων σε δίκτυο κινητής τηλ., όταν το σήμα Wi-Fi είναι χαμηλό"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Ενεργοποίηση 4x MSAA σε εφαρμογές OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Εντοπισμός σφαλμάτων σε λειτουργίες μη ορθογώνιας περιοχής"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Απόδοση GPU προφίλ"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Ενεργ. επιπ. εντ. σφ. GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Φόρτωση επιπ. εντοπ. σφ. GPU για εφαρμ. αντιμ. σφ."</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Κλίμακα κίνησης παραθύρου"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Κλίμακα κίνησης μετάβασης"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Κλίμ. διάρ. Animator"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index f351e70..c36b3ed 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Revisa la contraseña y vuelve a intentarlo"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Fuera de alcance"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"No se conectará automáticamente"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"No se detectó acceso a Internet"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"No hay acceso a Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Guardadas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Conexión automática mediante %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Conectado automáticamente mediante proveedor de calificación de red"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Conexión a través de %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Disponible a través de %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Conectado a Wi-Fi, sin conexión a Internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Conectado pero sin conexión a Internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"El punto de acceso está completo temporalmente"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Conexión a través de %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Disponible a través de %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Conexión a SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"No conectado al servidor de transferencia de archivo"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Conectado a dispositivo de entrada"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Conectado a un dispositivo para acceder a Internet"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Conexión a Internet local compartida con dispositivo"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Utilizar para acceso a Internet"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Conectado para Internet"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Compartiendo conexión"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Usar para acceder a Internet"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Usar para mapa"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Usar para acceder a la SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Utilizar para el audio multimedia"</string>
@@ -216,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Códec del audio Bluetooth LDAC: calidad de reproducción"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Seleccionar códec del audio Bluetooth LDAC:\nCalidad de reproducción"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Transmitiendo: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS mediante TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Si esta opción está habilitada, prueba DNS mediante TLS en el puerto 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS privado"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Selecciona el modo de DNS privado"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Desactivado"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunista"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Nombre de host del proveedor de DNS privado"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Ingresa el nombre de host del proveedor de DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opciones de certificación de pantalla inalámbrica"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar nivel de registro Wi-Fi; mostrar por SSID RSSI en el selector de Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Si habilitas esta opción, se priorizará el cambio de Wi-Fi a datos móviles cuando la señal de Wi-Fi sea débil"</string>
@@ -292,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Activar MSAA 4x en aplicaciones OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Depurar operaciones de recorte no rectangulares"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Represent. GPU del perfil"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Habilitar depuración GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Permitir capas de GPU para apps de depuración"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Ventana de escala de animación"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Transición de escala de animación"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Escala de duración de animador"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index d36db19..1f57e48 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -33,15 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Comprueba la contraseña y vuelve a intentarlo"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Fuera de rango"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"No se establecerá conexión automáticamente"</string>
- <!-- no translation found for wifi_no_internet (4663834955626848401) -->
- <skip />
+ <string name="wifi_no_internet" msgid="4663834955626848401">"No se ha detectado ningún acceso a Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Guardada por <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Conectada automáticamente a través de %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Conectado automáticamente a través de un proveedor de valoración de redes"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado a través de %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Disponible a través de %1$s"</string>
- <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Conexión sin Internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Punto de acceso temporalmente lleno"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Conectado a través de %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Disponible a través de %1$s"</string>
@@ -86,8 +84,7 @@
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Conectado a dispositivo de entrada"</string>
<string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Conectado para acceder a Internet"</string>
<string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Compartiendo conexión local con dispositivo"</string>
- <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
- <skip />
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Usar para acceder a Internet"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Usar para mapa"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Utilizar para acceso a tarjeta SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Utilizar para audio de medio"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index efbbac1..361d14d 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Kontrollige parooli ja proovige uuesti"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Pole vahemikus"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Automaatselt ei ühendata"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Interneti-ühendus puudub"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Juurdepääs Internetile puudub"</string>
<string name="saved_network" msgid="4352716707126620811">"Salvestas: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Ühendus loodi automaatselt teenusega %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Ühendus loodi automaatselt võrgukvaliteedi hinnangute pakkuja kaudu"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Ühendatud üksuse %1$s kaudu"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Saadaval üksuse %1$s kaudu"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Ühendatud, Interneti-ühendus puudub"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Ühendatud, Interneti-ühendus puudub"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Pääsupunkt on ajutiselt täis"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Ühendatud operaatori %1$s kaudu"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Saadaval operaatori %1$s kaudu"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Ühendatud SAP-iga"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Ei ole failiedastuse serveriga ühendatud"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Ühendatud sisendseade"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Ühendatud seadmega Internetti juurdepääsuks"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Kohaliku Interneti-ühenduse jagamine seadmega"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Interneti-juurdepääsuks kasutamine"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Interneti kasutamiseks seadmega ühend."</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Kohaliku Interneti-ühenduse jagamine seadmega"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Internetile juurdepääsuks kasutamine"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Kasuta kaardi jaoks"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM-kaardi juurdepääsuks kasutamine"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Kasuta meediumiheli jaoks"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Ei saanud seadmega <xliff:g id="DEVICE_NAME">%1$s</xliff:g> siduda vale PIN-koodi või parooli tõttu."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Seadmega <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ei saa sidet luua."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> hülgas sidumise."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Arvuti"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Peakomplekt"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Pildindus"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Kõrvaklapid"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Sisestatud välisseade"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"WiFi on välja lülitatud."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"WiFi-ühendus on katkestatud."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"WiFi: üks pulk."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetoothi LDAC-helikodek: taasesituskvaliteet"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Valige Bluetoothi LDAC-helikodek:\ntaasesituskvaliteet"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Voogesitus: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS TLS-i kaudu"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Kui on lubatud, katsetatakse DNS-i TLS-i kaudu (port 853)."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privaatne DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Valige privaatse DNS-i režiim"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Väljas"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunistlik"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Privaatse DNS-i teenusepakkuja hostinimi"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Sisestage DNS-i teenusepakkuja hostinimi"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Juhtmeta ekraaniühenduse sertifitseerimisvalikute kuvamine"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Suurenda WiFi logimistaset, kuva WiFi valijas SSID RSSI järgi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Kui seade on lubatud, asendatakse nõrga signaaliga WiFi-ühendus agressiivsemalt mobiilse andmesideühendusega"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Luba 4x MSAA OpenGL ES 2.0 rakendustes"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Silu klipi mittetäisnurksed toimingud"</string>
<string name="track_frame_time" msgid="6146354853663863443">"GPU renderduse profiil"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU silum. kihtide lubam."</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"GPU sil. kiht. laadim. lubam. silumisrakendustele"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Akna animatsiooni skaala"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Ülemineku animats. skaala"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Animaatori kestuse skaala"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index bc287bc..35917bb 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"گذرواژه را بررسی و دوباره امتحان کنید"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"در محدوده نیست"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"اتصال بهصورت خودکار انجام نمیشود"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"دسترسی به اینترنت وجود ندارد"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"بدون دسترسی به اینترنت"</string>
<string name="saved_network" msgid="4352716707126620811">"ذخیرهشده توسط <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"اتصال خودکار ازطریق %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"اتصال خودکار ازطریق ارائهدهنده رتبهبندی شبکه"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"متصل از طریق %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"در دسترس از طریق %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"متصل، بدون اینترنت"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"متصل، بدون اینترنت"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ظرفیت نقطه دسترسی موقتاً تکمیل شده است"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"متصل ازطریق %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"در دسترس ازطریق %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"متصل به SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"به سرور انتقال فایل متصل نیست"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"به دستگاه ورودی متصل شد"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"برای دسترسی به اینترنت، به دستگاه متصل شد"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"اشتراکگذاری اتصال اینترنت محلی با دستگاه"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"استفاده برای دسترسی به اینترنت"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"برای دسترسی به اینترنت، به دستگاه متصل شد"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"همرسانی اتصال اینترنت محلی با دستگاه"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"استفاده برای دسترسی به اینترنت"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"استفاده برای نقشه"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"استفاده برای دسترسی سیمکارت"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"استفاده برای رسانه صوتی"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"به خاطر یک پین یا کلیدواژه نادرست، مرتبطسازی با <xliff:g id="DEVICE_NAME">%1$s</xliff:g> انجام نشد."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"ارتباط با <xliff:g id="DEVICE_NAME">%1$s</xliff:g> امکانپذیر نیست."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> مرتبطسازی را رد کرد."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"رایانه"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"هدست"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"تلفن"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"تصویربرداری"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"هدفون"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"ورودی محیطی"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"بلوتوث"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi‑Fi خاموش است."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi قطع شد."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"یک نوار برای Wi‑Fi."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"کدک LDAC صوتی بلوتوث: کیفیت پخش"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"انتخاب کدک LDAC صوتی بلوتوث:\nکیفیت پخش"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"پخش جریانی: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS ازطریق امنیت لایه انتقال"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"درصورت فعال بودن، DNS ازطریق امنیت لایه انتقال در درگاه ۸۵۳ انجام شود."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS خصوصی"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"حالت DNS خصوصی را انتخاب کنید"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"خاموش"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"فرصتطلب"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"نام میزبان ارائهدهنده DNS خصوصی"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"نام میزبان ارائهدهنده DNS خصوصی را وارد کنید"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"نمایش گزینهها برای گواهینامه نمایش بیسیم"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"افزایش سطح گزارشگیری Wi‑Fi، نمایش به ازای SSID RSSI در انتخابکننده Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"زمانیکه فعال است، درشرایطی که سیگنال Wi-Fi ضعیف باشد، Wi‑Fi برای واگذاری اتصال داده به دستگاه همراه قویتر عمل خواهد کرد."</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"فعال کردن 4X MSAA در برنامههای OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"اشکالزدایی عملکردهای کلیپ غیرمربعی"</string>
<string name="track_frame_time" msgid="6146354853663863443">"پردازش GPU نمایه"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"فعال کردن لایههای اشکالزدایی GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"مجاز کردن بارگیری لایههای اشکالزدایی GPU برای برنامههای اشکالزدایی"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"مقیاس پویانمایی پنجره"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"مقیاس پویانمایی انتقالی"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"مقیاس طول مدت انیماتور"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 6742aca..869490a 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Tarkista salasana ja yritä uudelleen."</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Ei kantoalueella"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Yhteyttä ei muodosteta automaattisesti"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Ei internetyhteyttä"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Ei internetyhteyttä"</string>
<string name="saved_network" msgid="4352716707126620811">"Tallentaja: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Automaattinen yhteys muodostettu palvelun %1$s kautta"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Yhdistetty automaattisesti verkon arviointipalvelun kautta"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Yhdistetty seuraavan kautta: %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Käytettävissä seuraavan kautta: %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Yhdistetty, ei internetyhteyttä."</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Yhdistetty, ei internetyhteyttä"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Yhteyspiste tilapäisesti täynnä"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Yhdistetty, verkko: %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Käytettävissä, verkko: %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP-yhteys on muodostettu."</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Ei yhdistetty tiedostonsiirtopalvelimeen"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Yhdistetty syöttölaitteeseen"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Yhdistetty laitteen internetyhteyteen"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Paikallinen internetyhteys jaetaan laitteen kanssa"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Käytä internetyhteyteen"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Yhdistetty laitteeseen"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Jaetaan internetyhteys"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Käytä internetyhteyteen"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Käytä MAP-profiilille"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Käytetään SIM-kortin käyttöoikeuden määrittämiseen."</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Käytä median äänille"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Laiteparia laitteen <xliff:g id="DEVICE_NAME">%1$s</xliff:g> kanssa ei voitu muodostaa, koska PIN-koodi tai avain oli virheellinen."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Ei yhteyttä laitteeseen <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Laite <xliff:g id="DEVICE_NAME">%1$s</xliff:g> torjui laitepariyhteyden."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Tietokone"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Kuulokemikrofoni"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Puhelin"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Kuvannuslaite"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Kuulokkeet"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Syöttölisälaite"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi pois käytöstä"</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Ei Wi-Fi-yhteyttä"</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi-signaali – yksi palkki"</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth-äänen LDAC-koodekki: Toiston laatu"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Valitse Bluetooth-äänen LDAC-koodekki:\nToiston laatu"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Striimaus: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS ennen TLS:ää"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Jos tämä on käytössä, yritä käyttää DNS:ää mieluummin kuin TLS:ää portin 853 kautta."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Yksityinen DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Valitse yksityinen DNS-tila"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Pois käytöstä"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistinen"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Yksityisen DNS-tarjoajan isäntänimi"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Anna isäntänimi tai DNS-tarjoaja."</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Näytä langattoman näytön sertifiointiin liittyvät asetukset"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Lisää Wi‑Fin lokikirjaustasoa, näytä SSID RSSI -kohtaisesti Wi‑Fi-valitsimessa."</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Kun asetus on käytössä, datayhteys siirtyy helpommin Wi-Fistä matkapuhelinverkkoon, jos Wi-Fi-signaali on heikko."</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Ota käyttöön 4x MSAA OpenGL ES 2.0 -sovelluksissa"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Korjaa ei-suorakulmaisten leiketoimintojen virheet"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Profiilin GPU-hahmonnus"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU-virheenkorjaus päälle"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Salli GPU:n virheenkorjauskerrosten lataus"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Ikkuna"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Siirtymä"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Animaattori"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 1b78d30..6fbe49a 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Vérifiez le mot de passe et réessayez"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Hors de portée"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Reconnexion automatique impossible"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Aucun accès à Internet"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Aucun accès à Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Enregistrés par <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatiquement connecté par %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Connecté automatiquement par le fournisseur d\'avis sur le réseau"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Connecté par %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Accessible par %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Connecté, aucun accès à Internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connecté, aucun accès à Internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Le point d\'accès est temporairement plein"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Connecté par %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Accessible par %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Connecté au point d\'accès au service"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Connexion au serveur de transfert de fichiers non établie"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Connecté au périphérique d\'entrée"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Connecté à l\'appareil pour accès Internet"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Connexion Internet locale partagée"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Utiliser pour l\'accès à Internet"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Connecté à l\'appareil pour accès Internet"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Connexion Internet locale partagée avec appareil"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Utiliser pour l\'accès à Internet"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Utiliser pour la carte"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Utiliser pour l\'accès à la carte SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Utiliser pour les paramètres audio du support"</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Activer MSAA 4x dans les applications OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Déboguer opérations de découpage non rectangulaire"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Rendu GPU du profil"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Activ. couches débog. GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Autor. couches débog. GPU pour applis de débogage"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Échelle animation fenêtres"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Échelle anim. transitions"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Échelle durée animation"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 9238c21..10addbb 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Vérifiez le mot de passe et réessayez"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Hors de portée"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Reconnexion automatique impossible"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Aucun accès à Internet"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Aucun accès à Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Enregistré lors de : <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Connecté automatiquement via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Connecté automatiquement via un fournisseur d\'évaluation de l\'état du réseau"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Connecté via %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Disponible via %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Connecté, aucun accès à Internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connecté, aucun accès à Internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Point d\'accès temporairement plein"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Connecté via %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Disponible via %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Connecté au point d\'accès au service"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Connexion au serveur de transfert de fichiers non établie"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Connecté au périphérique d\'entrée"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Connecté à l\'appareil pour accès Internet"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Connexion Internet locale partagée"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Utiliser pour l\'accès à Internet"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Connecté à l\'appareil pour accès Internet"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Connexion Internet locale partagée"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Utiliser pour l\'accès à Internet"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Utiliser pour la carte"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Utiliser pour l\'accès à la carte SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Utiliser pour les paramètres audio du média"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Impossible d\'établir l\'association avec <xliff:g id="DEVICE_NAME">%1$s</xliff:g> en raison d\'un code ou d\'une clé d\'accès incorrects."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Impossible d\'établir la communication avec <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Association refusée par <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Ordinateur"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Casque"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Téléphone"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Imagerie"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Casque audio"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Périphérique d\'entrée"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi désactivé"</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi déconnecté"</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Signal Wi-Fi faible"</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codec audio Bluetooth LDAC : qualité de lecture"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Sélectionner le codec audio Bluetooth LDAC :\nQualité de lecture"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Diffusion : <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS sur TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Si l\'option est activée, essayez le protocole DNS sur TLS sur le port 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS privé"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Sélectionner le mode DNS privé"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Désactivé"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportuniste"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Nom d\'hôte du fournisseur DNS privé"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Saisissez le nom d\'hôte du fournisseur DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Afficher les options de la certification de l\'affichage sans fil"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Détailler plus infos Wi-Fi, afficher par RSSI de SSID dans outil sélection Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Si cette option est activée, le passage du Wi-Fi aux données mobiles est forcé en cas de signal Wi-Fi faible."</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Activer MSAA 4x dans les applications OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Déboguer opé. de découpage non rect."</string>
<string name="track_frame_time" msgid="6146354853663863443">"Rendu GPU du profil"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Activer couches débogage GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Autoriser charg. couches débogage GPU pour applis débogage"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Échelle animation fenêtres"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Échelle anim. transitions"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Échelle durée animation"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index a8d3cca..f5cf5f6 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Comproba o contrasinal e téntao de novo"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Non está dentro da zona de cobertura"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Non se conectará automaticamente"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Non hai acceso a Internet"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Sen acceso a Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Redes gardadas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Conectouse automaticamente a través de %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Conectada automaticamente a través dun provedor de valoración de rede"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado a través de %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Dispoñible a través de %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Conectado, pero sen Internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Conexión sen Internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"O punto de acceso está temporalmente cheo"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Conectado a través de %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Dispoñible a través de %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Conectado a SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Non conectado co servidor de transferencia de ficheiros"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Conectado ao dispositivo de entrada"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Conectado ao dispositivo para acceder a Internet"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Compartindo conexión a Internet co dispositivo"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Utilízase para o acceso a Internet"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Conectado ao dispositivo para acceder a Internet"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Compartindo conexión local a Internet co dispositivo"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Utiliza o perfil para o acceso a Internet"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Usar para o mapa"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Usar para acceso á SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Utilízase para audio multimedia"</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Activar MSAA 4x en aplicacións OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Depurar operacións recorte non rectangulares"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Perfil procesamento GPU"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Activar depuración da GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Permite capas da GPU para aplicación de depuración"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Escala animación da ventá"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Escala anim. transición"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Escala duración animador"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index e3f9746..f6bb039 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"પાસવર્ડ તપાસો અને ફરી પ્રયાસ કરો"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"રેન્જમાં નથી"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"આપમેળે કનેક્ટ કરશે નહીં"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"કોઈ ઇન્ટરનેટ ઍક્સેસ નથી"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"કોઈ ઇન્ટરનેટ ઍક્સેસ નથી"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા સચવાયું"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s દ્વારા સ્વત: કનેક્ટ થયેલ"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"નેટવર્ક રેટિંગ પ્રદાતા દ્વારા આપમેળે કનેક્ટ થયું"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s દ્વારા કનેક્ટ થયેલ"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s દ્વારા ઉપલબ્ધ"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"કનેક્ટ કર્યું, કોઈ ઇન્ટરનેટ નથી"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"કનેક્ટ કર્યું, કોઈ ઇન્ટરનેટ નથી"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ઍક્સેસ પૉઇન્ટ અસ્થાયીરૂપે ભરાયેલ છે"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s દ્વારા કનેક્ટ થયેલ"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s દ્વારા ઉપલબ્ધ"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP થી કનેક્ટ કરેલ"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ફાઇલ સ્થાનાંતરણ સેવાથી કનેક્ટ થયેલ નથી"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ઇનપુટ ઉપકરણ સાથે કનેક્ટ થયાં"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"ઇન્ટરનેટ ઍક્સેસ માટે ઉપકરણથી કનેક્ટેડ છે"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ઉપકરણ સાથે સ્થાનિક ઇન્ટરનેટ કનેક્શન શેર કરે છે"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ઇન્ટરનેટ ઍક્સેસ માટે ઉપયોગ કરો"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"ઇન્ટરનેટ ઍક્સેસ માટે ઉપકરણથી કનેક્ટેડ છીએ"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"ઉપકરણ સાથે સ્થાનિક ઇન્ટરનેટ કનેક્શન શેર કરી રહ્યાં છીએ"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"ઇન્ટરનેટ ઍક્સેસ માટે ઉપયોગ કરો"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"નકશા માટે વાપરો"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"સિમ ઍક્સેસ માટે ઉપયોગ કરો"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"મીડિયા ઑડિઓ માટે ઉપયોગ કરો"</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 એપ્લિકેશન્સમાં 4x MSAA સક્ષમ કરો"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"બિન-લંબચોરસ ક્લિપ કામગીરી ડીબગ કરો"</string>
<string name="track_frame_time" msgid="6146354853663863443">"પ્રોફાઇલ GPU રેન્ડરિંગ"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU ડિબગ સ્તરોને સક્ષમ કરો"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"ડિબગ ઍપ માટે GPU ડિબગ સ્તરો લોડ કરવાની મંજૂરી આપો"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"વિંડો એનિમેશન સ્કેલ"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"સંક્રમણ એનિમેશન સ્કેલ"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"એનિમેટર અવધિ સ્કેલ"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 14095f4..826bab3 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -33,15 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"पासवर्ड जाँचें और दोबारा कोशिश करें"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"रेंज में नहीं"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"अपने आप कनेक्ट नहीं होगा"</string>
- <!-- no translation found for wifi_no_internet (4663834955626848401) -->
- <skip />
+ <string name="wifi_no_internet" msgid="4663834955626848401">"इंटरनेट नहीं है"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> के द्वारा सहेजा गया"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s के ज़रिए ऑटोमैटिक रूप से कनेक्ट है"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"नेटवर्क रेटिंग प्रदाता के ज़रिए अपने आप कनेक्ट है"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s के द्वारा उपलब्ध"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s के द्वारा उपलब्ध"</string>
- <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"कनेक्ट हो गया है, लेकिन इंटरनेट नहीं है"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"एक्सेस पॉइंट फ़िलहाल भरा हुआ है"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s के ज़रिए कनेक्ट"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s के ज़रिए उपलब्ध"</string>
@@ -86,8 +84,7 @@
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"इनपुट डिवाइस से कनेक्ट किया गया"</string>
<string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"इंटरनेट के लिए डिवाइस से कनेक्ट है"</string>
<string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"डिवाइस से इंटरनेट शेयर हो रहा है"</string>
- <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
- <skip />
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"इंटरनेट से जुड़ने के लिए इस्तेमाल करें"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"मानचित्र के लिए उपयोग करें"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"सिम ऐक्सेस के लिए उपयोग करें"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"मीडिया ऑडियो के लिए उपयोग करें"</string>
@@ -375,10 +372,10 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"चार्ज नहीं हो रही है"</string>
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"प्लग इन है, अभी चार्ज नहीं हो सकती"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"पूरी"</string>
- <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"व्यवस्थापक द्वारा नियंत्रित"</string>
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"इसका नियंत्रण एडमिन के पास है"</string>
<string name="enabled_by_admin" msgid="5302986023578399263">"व्यवस्थापक ने सक्षम किया है"</string>
<string name="disabled_by_admin" msgid="8505398946020816620">"व्यवस्थापक ने अक्षम किया है"</string>
- <string name="disabled" msgid="9206776641295849915">"अक्षम किया गया"</string>
+ <string name="disabled" msgid="9206776641295849915">"बंद किया गया"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"अनुमति है"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"अनुमति नहीं है"</string>
<string name="install_other_apps" msgid="6986686991775883017">"अनजान ऐप इंस्टॉल करें"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index c134970..514f648 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Provjerite zaporku i pokušajte ponovo"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u rasponu"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Neće se povezati automatski"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Nema pristupa internetu"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Nema pristupa internetu"</string>
<string name="saved_network" msgid="4352716707126620811">"Spremila aplik. <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatski povezan putem %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatski povezan putem ocjenjivača mreže"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Povezano putem %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Dostupno putem %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Povezano, bez interneta"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Povezano, bez interneta"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Pristupna je točka privremeno puna"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Povezano putem mreže %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Dostupno putem mreže %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Povezano sa SAP-om"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Niste povezani s poslužiteljem za prijenos datoteka"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Povezano s ulaznim uređajem"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Povezano s uređajem za pristup internetu"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Dijeljenje lokalne internetske veze s uređajem"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Upotrijebi za pristup internetu"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Povezano s uređajem za pristup internetu"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Dijeljenje lokalne internetske veze s uređajem"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Upotrijebi za pristup internetu"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Upotreba za kartu"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Upotrijebi za pristup SIM-u"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Koristi za medijski zvuk"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Uparivanje s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> nije bilo moguće zbog netočnog PIN-a ili zaporke."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Komunikacija s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> nije moguća."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Uparivanje odbio uređaj <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Računalo"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Slušalice s mikrofonom"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Snimanje"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Slušalice"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Periferni uređaj za unos"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi je isključen."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi je isključen."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi signal ima jedan stupac."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Kodek za Bluetooth Audio LDAC: kvaliteta reprodukcije"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Odaberi kodek za Bluetooth Audio LDAC:\nkvaliteta reprodukcije"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Strujanje: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS putem TLS-a"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Ako je omogućeno, pokušava se upotrijebiti DNS putem TLS-a na priključku 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privatni DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Odaberite način privatnog DNS-a"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Isključeno"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunistički"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Naziv hosta davatelja usluge privatnog DNS-a"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Unesite naziv hosta davatelja usluge DNS-a"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Prikaži opcije za certifikaciju bežičnog prikaza"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećana razina prijave na Wi‑Fi, prikaz po SSID RSSI-ju u Biraču Wi‑Fi-ja"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Ako je omogućeno, Wi-Fi će aktivno prebacivati podatkovnu vezu mobilnoj mreži kada je Wi-Fi signal slab."</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Omogući 4x MSAA u aplikacijama OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Otkloni pogreške operacija nepravokutnog isječka"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Profil GPU prikazivanja"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Omogući slojeve za otklanjanje pogrešaka GPU-a"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Omogući učitavanje slojeva za otklanjanje pogrešaka GPU-a za aplikacije za otklanjanje pogrešaka"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Brzina animacije prozora"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Brzina animacije prijelaza"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Razmjer duljine animatora"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index da206cb..9c94579 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Ellenőrizze a jelszót, majd próbálkozzon újra"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Hatókörön kívül"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nem csatlakozik automatikusan"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Nincs internet-hozzáférés"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Nincs internet-hozzáférés"</string>
<string name="saved_network" msgid="4352716707126620811">"Mentette: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatikusan csatlakozott a következőn keresztül: %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatikusan csatlakozott a hálózatértékelés szolgáltatóján keresztül"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Csatlakozva a következőn keresztül: %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Elérhető a következőn keresztül: %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Csatlakozva, nincs internetelérés"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Csatlakozva, nincs internet-hozzáférés"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"A hozzáférési pont átmenetileg megtelt"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Csatlakozva a következőn keresztül: %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Elérhető a következőn keresztül: %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Csatlakozva az SAP-hoz"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nincs csatlakozva a fájlküldő szerverhez"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Beviteli eszköz csatlakoztatva"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Eszközhöz csatlakozik az interneteléréshez"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Helyi internetkapcsolat megosztva az eszközzel"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Használat internetelérésre"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Internetelérés miatt csatlakozik az eszközhöz"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Helyi internetkapcsolat megosztása az eszközzel"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Használat internetelérésre"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Használat a térképhez"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Használat SIM-elérésre"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Felhasználás az eszköz hangjához"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"A párosítás sikertelen volt a(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszközzel hibás PIN-kód vagy jelszó miatt."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Nem lehet kommunikálni a(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszközzel."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"A(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszköz elutasította a párosítást."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Számítógép"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Headset"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Képalkotó"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Fejhallgató"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Beviteli periféria"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi kikapcsolva."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Nincs Wi-Fi-kapcsolat."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi-jel: egy sáv."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth LDAC hangkodek: lejátszási minőség"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Bluetooth LDAC hangkodek kiválasztása:\nlejátszási minőség"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streamelés: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"TLS-en keresztüli DNS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"TLS-en keresztüli DNS megkísérlése a 853-as porton, ha engedélyezve van."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privát DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"„Privát DNS” mód kiválasztása"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Ki"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunista"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Privát DNS-szolgáltató gazdagépneve"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Adja meg a DNS-szolgáltató gazdagépnevét"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Vezeték nélküli kijelző tanúsítványával kapcsolatos lehetőségek megjelenítése"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi-naplózási szint növelése, RSSI/SSID megjelenítése a Wi‑Fi-választóban"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Ha engedélyezi, a Wi-Fi agresszívebben fogja átadni az adatkapcsolatot a mobilhálózatnak gyenge Wi-Fi-jel esetén"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"A 4x MSAA engedélyezése az OpenGL ES 2.0-nál"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Nem négyzetes kivágási műveletek hibakeresése"</string>
<string name="track_frame_time" msgid="6146354853663863443">"GPU-renderelési profil"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU-hibakeresési rétegek engedélyezése"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"GPU-hibakeresési rétegek betöltésének engedélyezése"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Ablakanimáció tempója"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Áttűnési animáció tempója"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Animáció tempója"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 34f471b..80431a0 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Ստուգեք գաղտնաբառը և նորից փորձեք"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Ընդգրկույթից դուրս է"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Չի միանա ավտոմատ"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Ինտերնետ կապ չկա"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Ինտերնետ կապ չկա"</string>
<string name="saved_network" msgid="4352716707126620811">"Պահել է՝ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Ավտոմատ կերպով կապակցվել է %1$s-ի միջոցով"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Ավտոմատ կերպով միացել է ցանցի վարկանիշի ծառայության մատակարարի միջոցով"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Կապակցված է %1$s-ի միջոցով"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Հասանելի է %1$s-ի միջոցով"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Կապակցված է առանց համացանցի"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Միացված է, սակայն ինտերնետ կապ չկա"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Հասանելիության կետը ժամանակավորապես լիքն է"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Միացված է %1$s-ի միջոցով"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Հասանելի է %1$s-ի միջոցով"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Կապակցված է SAP-ին"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Ֆայլերը փոխանցող սերվերի հետ կապ չկա"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Միացված է մուտքային սարքին"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Կապակցված է սարքին` ինտերնետ մուտք գործելու համար"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Տեղային ինտերնետ կապի տարածում սարքի հետ"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Օգտագործել ինտերնետ մուտք գործելու համար"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Միացված է սարքին` ինտերնետ մտնելու համար"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Տեղային ինտերնետ կապի տարածում սարքի հետ"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Օգտագործել՝ ինտերնետ մուտք գործելու համար"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Օգտագործել քարտեզի համար"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM քարտի օգտագործում"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Օգտագործել մեդիա աուդիոյի համար"</string>
@@ -216,7 +216,7 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth աուդիո LDAC կոդեկ՝ նվագարկման որակ"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Ընտրեք Bluetooth աուդիո LDAC կոդեկը՝\nնվագարկման որակ"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Հեռարձակում՝ <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Անհատական DNS սերվեր"</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Անհատական DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Ընտրեք անհատական DNS սերվերի ռեժիմը"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Անջատված է"</string>
<string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Ճկուն"</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Միացնել 4x MSAA-ը OpenGL ES 2.0 ծրագրերում"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Կարգաբերել ոչ-ուղղանկյուն կտրվածքի գործողությունները"</string>
<string name="track_frame_time" msgid="6146354853663863443">"GPU տվյալներ"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Միացնել GPU վրիպազերծման շերտերը"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Թույլատրել GPU վրիպազերծման շերտերի բեռնումը վրիպազերծման հավելվածների համար"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Պատուհանի շարժապատկերի սանդղակ"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Անցումային շարժական սանդղակ"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Շարժանկարի տևողության սանդղակ"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 7e2848f..536d22e 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Periksa sandi dan coba lagi"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Tidak dalam jangkauan"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Tidak akan tersambung otomatis"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Tidak ada akses internet"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Tidak ada akses internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Disimpan oleh <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Tersambung otomatis melalui %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Otomatis tersambung melalui penyedia rating jaringan"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Terhubung melalui %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Tersedia melalui %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Tersambung, tidak ada internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Tersambung, tidak ada internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Titik akses penuh untuk sementara"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Tersambung melalui %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Tersedia melalui %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Terhubung ke SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Tidak tersambung kepada server transfer file"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Terhubung ke perangkat masukan"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Tersambung ke perangkat untuk akses Internet"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Berbagi sambungan Internet lokal dengan perangkat"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Digunakan untuk akses internet"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Terhubung ke perangkat untuk akses internet"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Berbagi sambungan internet lokal dengan perangkat"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Digunakan untuk akses internet"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Gunakan untuk peta"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Gunakan untuk akses SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Gunakan untuk audio media"</string>
@@ -94,11 +94,18 @@
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Sandingkan"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SANDINGKAN"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Batal"</string>
- <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Penyandingan memberi akses ke kontak dan riwayat panggilan saat tersambung"</string>
+ <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Penyandingan memberi akses ke kontak dan histori panggilan saat tersambung"</string>
<string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Tidak dapat menyandingkan dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Tidak dapat menyandingkan dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> karena PIN atau kode sandi salah."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Tidak dapat berkomunikasi dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Penyandingan ditolak oleh <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Komputer"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Headset"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telepon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Pencitraan"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Headphone"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Periferal Masukan"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi tidak aktif."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi tidak tersambung."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi satu baris."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codec LDAC Audio Bluetooth: Kualitas Pemutaran"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Pilih Codec LDAC Audio Bluetooth:\nKualitas Pemutaran"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS melalui TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Jika diaktifkan, coba DNS melalui TLS pada port 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS Pribadi"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Pilih Mode DNS Pribadi"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Nonaktif"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunistik"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Hostname penyedia DNS pribadi"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Masukkan hostname penyedia DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Tampilkan opsi untuk sertifikasi layar nirkabel"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Tingkatkan level pencatatan log Wi-Fi, tampilkan per SSID RSSI di Pemilih Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Jika diaktifkan, Wi-Fi akan menjadi lebih agresif dalam mengalihkan sambungan data ke seluler saat sinyal Wi-Fi lemah"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Aktifkan 4x MSAA dalam aplikasi OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Debug operasi klip non-kotak"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Penguraian GPU profil"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Aktifkan lapisan debug GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Izinkan memuat lapisan debug GPU untuk aplikasi debug"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Skala animasi jendela"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Skala animasi transisi"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Skala durasi animator"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 5f4d401..a29fbe5 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Athugaðu aðgangsorðið og reyndu aftur"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Ekkert samband"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Mun ekki tengjast sjálfkrafa"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Enginn netaðgangur"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Enginn netaðgangur"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> vistaði"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Sjálfkrafa tengt um %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Sjálfkrafa tengt um netgæðaveitu"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Tengt í gegnum %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Í boði í gegnum %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Tengt, enginn internetaðgangur"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Tengt, enginn netaðgangur"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Aðgangsstaður tímabundið fullur"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Tengt í gegnum %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Í boði í gegnum %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Tengt við SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Ekki tengt við skráaflutningsþjón."</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Tengt við inntakstæki"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Tengt við tæki til að fá netaðgang"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Internettengingu deilt með tæki"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Nota fyrir netaðgang"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Tengt við tæki til að fá netaðgang"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Nettengingu deilt með tæki"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Nota fyrir netaðgang"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Nota fyrir kort"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Nota fyrir aðgang að SIM-korti"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Nota fyrir hljóð efnisspilunar"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Ekki tókst að para við <xliff:g id="DEVICE_NAME">%1$s</xliff:g> þar sem PIN-númer eða aðgangslykill er rangur."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Ekki er hægt að eiga samskipti við <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> hafnaði pörun."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Tölva"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Höfuðtól"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Sími"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Myndherming"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Heyrnartól"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Jaðartæki með inntak"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Slökkt á Wi-Fi."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi ótengt."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi: Eitt strik."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth LDAC-hljóðkóðari: gæði spilunar"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Velja Bluetooth LDAC-hljóðkóðara:\ngæði spilunar"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streymi: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS yfir TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Ef kveikt er á þessu, reyna DNS yfir TLS á gátt 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Lokað DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Velja lokaða DNS-stillingu"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Slökkt"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Eftir hentugleika"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Hýsilheiti lokaðrar DNS-veitu"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Slá inn hýsilheiti DNS-veitu"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Sýna valkosti fyrir vottun þráðlausra skjáa"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Auka skráningarstig Wi-Fi, sýna RSSI fyrir hvert SSID í Wi-Fi vali"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Þegar þetta er virkt mun Wi-Fi skipta hraðar yfir í farsímagagnatengingu þegar Wi-Fi-tenging er léleg"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Virkja 4x MSAA í OpenGL ES 2.0 forritum"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Villuleita klippt svæði sem ekki eru rétthyrnd"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Greina skjákortsteiknun"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Virkja villuleit skják."</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Leyfa villuleit skjákorts fyrir villuleit forrita"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Kvarði gluggahreyfinga"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Lengd hreyfiumbreytinga"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Tímalengd hreyfiáhrifa"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 439fea1..df0157a 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Controlla la password e riprova"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Fuori portata"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Non verrà eseguita la connessione automatica"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Nessun accesso a Internet"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Nessun accesso a Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Salvata da <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Collegato automaticamente tramite %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Collegato automaticamente tramite fornitore di servizi di valutazione rete"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Collegato tramite %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Disponibile tramite %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Connesso senza Internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connesso, senza Internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Punto di accesso momentaneamente al completo"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Connesso tramite %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Disponibile tramite %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Collegato al SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Non collegato al server di trasferimento file"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Connesso a dispositivo di input"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Connesso a dispositivo per accesso Internet"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Connessione Internet locale condivisa con dispositivo"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Usa per accesso Internet"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Connesso a dispositivo per accesso Internet"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Connessione Internet locale condivisa con dispositivo"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Usa per accesso a Internet"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Utilizza per la mappa"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Utilizza per accesso SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Usa per audio media"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Impossibile eseguire l\'accoppiamento con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. La passkey o il PIN è errato."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Impossibile comunicare con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Accoppiamento rifiutato da <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Computer"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Auricolare"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefono"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Sistema di imaging"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Cuffie"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Periferica di immissione"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi non attivo."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Rete Wi-Fi scollegata."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi: una barra."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codec LDAC audio Bluetooth: qualità di riproduzione"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Seleziona il codec LDAC audio Bluetooth:\nQualità di riproduzione"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS tramite TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Se l\'opzione è attiva, prova DNS tramite TLS sulla porta 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS privato"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Seleziona modalità DNS privato"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Non attiva"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistica"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Nome host del provider DNS privato"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Inserisci il nome host del provider DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra opzioni per la certificazione display wireless"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumenta il livello di registrazione Wi-Fi, mostrando il SSID RSSI nel selettore Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Con questa impostazione attivata, il Wi-Fi è più aggressivo nel passare la connessione dati al cellulare, con segnale Wi-Fi basso"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Attiva MSAA 4x in applicazioni OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Debug operazioni ritaglio non rettangolare"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Rendering GPU"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Attiva livelli debug GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Consenti caricamento livelli debug GPU app debug"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Scala animazione finestra"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Scala animazione transizione"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Scala durata animatore"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index c5f4f85..0d78f26 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"בדוק את הסיסמה ונסה שוב"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"מחוץ לטווח"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"לא יתבצע חיבור באופן אוטומטי"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"אין גישה לאינטרנט"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"אין גישה לאינטרנט"</string>
<string name="saved_network" msgid="4352716707126620811">"נשמר על ידי <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"מחובר אוטומטית דרך %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"מחובר אוטומטית דרך ספק של דירוג רשת"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"מחובר דרך %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"זמינה דרך %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"מחובר. אין אינטרנט"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"מחובר. אין אינטרנט"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"נקודת הגישה מלאה באופן זמני"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"מחובר לרשת של %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"זמינה דרך %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"מחובר ל-SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"לא מחובר לשרת העברת קבצים"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"מחובר למכשיר קלט"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"מחובר למכשיר לצורך גישה לאינטרנט"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"משתף חיבור אינטרנט מקומי עם מכשיר"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"השתמש עבור גישה לאינטרנט"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"יש חיבור למכשיר לצורך גישה לאינטרנט"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"המערכת משתפת חיבור אינטרנט מקומי עם המכשיר"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"השתמש עבור גישה לאינטרנט"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"שימוש עבור מפה"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"השתמש לגישה של SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"השתמש עבור אודיו של מדיה"</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"הפעל 4x MSAA ביישומי OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"ניפוי באגים בפעולות באזור שאינו מלבני"</string>
<string name="track_frame_time" msgid="6146354853663863443">"עיבוד פרופיל ב-GPU"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"הפעלת שכבות לניפוי באגים ב-GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"טעינת שכבות לניפוי באגים ב-GPU לאפליקציות ניפוי באגים"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"קנה מידה לאנימציה של חלון"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"קנה מידה לאנימציית מעבר"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"קנה מידה למשך זמן אנימציה"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index b66f95f..4dddcd7 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"パスワードを確認して、もう一度お試しください"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"圏外"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"自動的に接続されません"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"インターネットに接続していません"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"インターネット接続なし"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g>で保存"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s 経由で自動的に接続しています"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ネットワーク評価プロバイダ経由で自動的に接続しています"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s経由で接続"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s経由で使用可能"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"接続済み、インターネットは利用できません"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"接続済み、インターネット接続なし"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"アクセス ポイントが一時的にいっぱいです"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s 経由で接続済み"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s 経由で使用可能"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAPに接続"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ファイル転送サーバーに接続しない"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"入力デバイスに接続されています"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"インターネットアクセス用に接続"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ローカルインターネット接続をデバイスと共有"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"インターネットアクセスに使用する"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"インターネット アクセス用にデバイスに接続"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"ローカル インターネット接続をデバイスと共有"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"インターネット アクセスに使用する"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"地図に使用"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIMアクセスに使用"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"メディアの音声に使用"</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0アプリで4x MSAAを有効にする"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"非矩形クリップ操作をデバッグ"</string>
<string name="track_frame_time" msgid="6146354853663863443">"GPUレンダリングのプロファイル作成"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU デバッグレイヤの有効化"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"デバッグアプリに GPU デバッグレイヤの読み込みを許可"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"ウィンドウアニメスケール"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"トランジションアニメスケール"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Animator再生時間スケール"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index f455324..d202993 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"გადაამოწმეთ პაროლი და ხელახლა ცადეთ"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"არ არის დიაპაზონში"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"ავტომატურად დაკავშირება ვერ მოხერხდება"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"ინტერნეტთან კავშირი არ არის"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"ინტერნეტ-კავშირი არ არის"</string>
<string name="saved_network" msgid="4352716707126620811">"შენახული <xliff:g id="NAME">%1$s</xliff:g>-ის მიერ"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"ავტომატურად დაკავშირდა %1$s-ის მეშვეობით"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ავტომატურად დაკავშირდა ქსელის ხარისხის შეფასების პროვაიდერის მეშვეობით"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s-ით დაკავშირებული"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"ხელმისაწვდომია %1$s-ით"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"დაკავშირებულია, ინტერნეტის გარეშე"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"დაკავშირებულია, ინტერნეტის გარეშე"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"წვდომის წერტილი დროებით გადატვირთულია"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s-ით დაკავშირებული"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"ხელმისაწვდომია %1$s-ით"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP-თან დაკავშირებული"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"არ არის დაკავშირებული ფაილების ტრანსფერის სერვერთან"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"დაკავშირებულია შეყვანის მოწყობილობასთან"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"დაკავშირებულია მოწყობილობასთან ინტერნეტთან წვდომისთვის"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ლოკალური კავშირის გაზიარება მოწყობილობასთან"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"გამოიყენე ინტერნეტთან წვდომისთვის"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"დაკავშირებულია მოწყობილობასთან ინტერნეტთან წვდომისთვის"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"მოწყობილობასთან ზიარდება ადგ. ინტერნეტ-კავშირი"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"ინტერნეტზე წვდომისთვის გამოყენება"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"რუკაზე გამოყენება"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"გამოყენება SIM წვდომისთვის"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"მედია აუდიოსთვის გამოყენება"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>-თან დაწყვილება ვერ მოხერხდა, რადგან PIN ან გასაღები არასწორია."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"შეუძლებელია <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-თან კომუნიკაცია."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"დაწყვილება უარყოფილია <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ის მიერ."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"კომპიუტერი"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"ყურსაცვამი"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"ტელეფონი"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"გამოსახულებათა დამუშავების მოწყობილობა"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"ყურსასმენი"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"შეყვანის პერიფერიული მოწყობილობა"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"WiFi გამორთულია."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"WiFi არ არის დაკავშირებული."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"WiFi სიგნალი ერთ ზოლზეა."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth აუდიოს LDAC კოდეკის დაკვრის ხარისხი"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"აირჩიეთ Bluetooth აუდიოს LDAC კოდეკის\nდაკვრის ხარისხი"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"სტრიმინგი: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS-ის TLS-ის მეშვეობით გადაცემა"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"ჩართვის შემთხვევაში, DNS-ის TLS-ის მეშვეობით გადაცემის ცდა, პორტზე 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"პირადი DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"აირჩიეთ პირადი DNS რეჟიმი"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"გამორთული"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"ოპორტუნისტული"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"პირადი DNS პროვაიდერის სერვერის სახელი"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"შეიყვანეთ DNS პროვაიდერის სერვერის სახელი"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"უსადენო ეკრანის სერტიფიცირების ვარიანტების ჩვენება"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi-ს აღრიცხვის დონის გაზრდა, Wi‑Fi ამომრჩეველში ყოველ SSID RSSI-ზე ჩვენება"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"ჩართვის შემთხვევაში, Wi‑Fi უფრო აქტიურად შეეცდება მობილურ ინტერნეტზე გადართვას, როცა Wi‑Fi სიგნალი სუსტია"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"4x MSAA-ის ჩართვა OpenGL ES 2.0 აპში."</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"არა-მართკუთხა კლიპ-ოპერაციების გამართვა"</string>
<string name="track_frame_time" msgid="6146354853663863443">"GPU რენდერის პროფილი"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU-ს შეცდომების გამართვის შრეების ჩართვა"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"გასამართი აპებისთვის GPU-ს შეცდომების გამართვის შრეების გაშვების დაშვება"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"ფანჯარა: მასშტაბი"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"გადასვლის მასშტაბი"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"ანიმაციების ხანგრძლივობის მასშტაბი"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 223a328..9f7c166 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Құпия сөзді тексеріп, әрекетті қайталаңыз"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Аумақта жоқ"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Автоматты қосылмайды"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Интернетпен байланыс жоқ"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Интернетпен байланыс жоқ"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> сақтаған"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s арқылы автоматты қосылды"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Желі рейтингі провайдері арқылы автоматты түрде қосылған"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s арқылы қосылған"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s арқылы қолжетімді"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Қосылған, интернет жоқ"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Қосылған, интернет жоқ"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Кіру нүктесі уақытша бос емес"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s арқылы қосылды"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s арқылы қолжетімді"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP жүйесіне қосылған"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Файл жіберу серверіне жалғанбаған"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Кіріс құрылғысына косылған"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Құрылғыға интернетке кіру үшін жалғанған"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Жергілікті интернет байланысын құрылғымен ортақ пайдалану"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Интернетке кіру үшін қолдану"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Интернетке кіру үшін құрылғымен байланыстырылған"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Жергілікті интернет байланысын құрылғымен бөлісуде"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Интернетке кіру үшін қолдану"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Карта үшін қолдану"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM картасына кіру үшін пайдалану"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Медиа аудиосы үшін қолдану"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысымен жұптала алмады, себебі PIN немесе кілтсөз дұрыс емес."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысымен қатынаса алмайды"</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысы жұпталудан бас тартты."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Компьютер"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Құлақаспап жинағы"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Телефон"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Бейне құралы"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Құлақаспап"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Кіріс құралы"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi өшірулі."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi ажыратылған."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi сигналы — бір жолақ."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth LDAC аудиокодегі: ойнату сапасы"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Bluetooth LDAC аудиокодегін таңдау:\nойнату сапасы"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Трансляция: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"TLS бойынша DNS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Қосулы болса, 853 портында DNS жүйесін TLS протоколы арқылы қосып көріңіз."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Жеке DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Жеке DNS режимін таңдаңыз"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Өшіру"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Кездейсоқ"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Жеке DNS провайдерінің хост атауы"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS провайдерінің хост атауын енгізіңіз"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Сымсыз дисплей растау опцияларын көрсету"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi жур. тір. дең. арт., Wi‑Fi желісін таңдағышта әр SSID RSSI бойынша көрсету"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Wi‑Fi сигналы әлсіз болғанда, деректер байланысы мәжбүрлі түрде мобильдік желіге ауысады"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"4x MSAA функциясын OpenGL ES 2.0 (ашық графикалық кітапхана) қолданбаларында іске қосу"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Тіктөртбұрышты емес кесу жұмыстарын жөндеу"</string>
<string name="track_frame_time" msgid="6146354853663863443">"GPU жұмысын жазу"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU түзету қабаттарын қосу"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"GPU түзету қабаттарының жүктелуіне рұқсат ету"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Терезе анимациясының өлшемі"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Ауысу анимациясының өлшемі"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Аниматор ұзақтығының межесі"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 02575ff..59fca43 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -33,15 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"សូមពិនិត្យមើលពាក្យសម្ងាត់ រួចព្យាយាមម្ដងទៀត"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"នៅក្រៅតំបន់"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"នឹងមិនភ្ជាប់ដោយស្វ័យប្រវត្តិទេ"</string>
- <!-- no translation found for wifi_no_internet (4663834955626848401) -->
- <skip />
+ <string name="wifi_no_internet" msgid="4663834955626848401">"មិនមានការតភ្ជាប់អ៊ីនធឺណិតទេ"</string>
<string name="saved_network" msgid="4352716707126620811">"បានរក្សាទុកដោយ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"បានភ្ជាប់ដោយស្វ័យប្រវត្តិតាមរយៈ %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"បានភ្ជាប់ដោយស្វ័យប្រវត្តិតាមរយៈក្រុមហ៊ុនផ្តល់ការវាយតម្លៃលើបណ្តាញ"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"បានភ្ជាប់តាមរយៈ %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"មានតាមរយៈ %1$s"</string>
- <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"បានភ្ជាប់ ប៉ុន្តែគ្មានអ៊ីនធឺណិតទេ"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ចំណុចចូលប្រើពេញជាបណ្តោះអាសន្ន"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"បានភ្ជាប់តាមរយៈ %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"មានតាមរយៈ %1$s"</string>
@@ -86,8 +84,7 @@
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"បានតភ្ជាប់ទៅឧបករណ៍បញ្ចូល"</string>
<string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"បានភ្ជាប់ទៅឧបករណ៍ដើម្បីចូលប្រើអ៊ីនធឺណិត"</string>
<string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"កំពុងចែករំលែកការភ្ជាប់អ៊ីនធឺណិតមូលដ្ឋានជាមួយឧបករណ៍"</string>
- <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
- <skip />
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"ប្រើសម្រាប់ការតភ្ជាប់អ៊ីនធឺណិត"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"ប្រើសម្រាប់ផែនទី"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"ប្រើសម្រាប់ចូលដំណើរការស៊ីម"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"ប្រើសម្រាប់សំឡេងមេឌៀ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index d7ab9fe..5a9bfb7 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"ಪಾಸ್ವರ್ಡ್ ಪರಿಶೀಲಿಸಿ ಮತ್ತು ಪುನಃ ಪ್ರಯತ್ನಿಸಿ"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"ವ್ಯಾಪ್ತಿಯಲ್ಲಿಲ್ಲ"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವಿಲ್ಲ"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವಿಲ್ಲ"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ನಿಂದ ಉಳಿಸಲಾಗಿದೆ"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s ಮೂಲಕ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ನೆಟ್ವರ್ಕ್ ರೇಟಿಂಗ್ ಒದಗಿಸುವವರ ಮೂಲಕ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ಮೂಲಕ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s ಮೂಲಕ ಲಭ್ಯವಿದೆ"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ, ಇಂಟರ್ನೆಟ್ ಇಲ್ಲ"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ, ಇಂಟರ್ನೆಟ್ ಇಲ್ಲ"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ಪ್ರವೇಶ ಕೇಂದ್ರ ತಾತ್ಕಾಲಿಕವಾಗಿ ಭರ್ತಿಯಾಗಿದೆ"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s ಮೂಲಕ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s ಮೂಲಕ ಲಭ್ಯವಿದೆ"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP ಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ಫೈಲ್ ವರ್ಗಾವಣೆ ಸರ್ವರ್ಗೆ ಸಂಪರ್ಕಗೊಳ್ಳಲಿಲ್ಲ"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ಇನ್ಪುಟ್ ಸಾಧನಕ್ಕೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶಕ್ಕಾಗಿ ಸಾಧನಕ್ಕೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ಸಾಧನದ ಜೊತೆಗೆ ಸ್ಥಳೀಯ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶಕ್ಕಾಗಿ ಬಳಸಿ"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶಕ್ಕಾಗಿ ಸಾಧನಕ್ಕೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"ಸಾಧನದ ಜೊತೆಗೆ ಸ್ಥಳೀಯ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶಕ್ಕಾಗಿ ಬಳಸಿ"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"ನಕ್ಷೆಗಾಗಿ ಬಳಸಿ"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"ಸಿಮ್ ಪ್ರವೇಶಕ್ಕೆ ಬಳಸಿ"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"ಮಾಧ್ಯಮ ಆಡಿಯೋ ಬಳಸು"</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 ಅಪ್ಲಿಕೇಶನ್ಗಳಲ್ಲಿ 4x MSAA ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"ಆಯತಾಕಾರವಲ್ಲದ ಕ್ಲಿಪ್ ಕಾರ್ಯಾಚರಣೆ ಡೀಬಗ್"</string>
<string name="track_frame_time" msgid="6146354853663863443">"GPU ಪ್ರೊಫೈಲ್ ಸಲ್ಲಿಕೆ"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU ಡೀಬಗ್ ಲೇಯರ್ಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"ಡೀಬಗ್ ಅಪ್ಲಿಕೇಶನ್ಗಳಿಗಾಗಿ GPU ಡೀಬಗ್ ಲೇಯರ್ಗಳನ್ನು ಲೋಡ್ ಮಾಡುವುದನ್ನು ಅನುಮತಿಸಿ"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Window ಅನಿಮೇಶನ್ ಸ್ಕೇಲ್"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"ಪರಿವರ್ತನೆ ಅನಿಮೇಶನ್ ಸ್ಕೇಲ್"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"ಅನಿಮೇಟರ್ ಅವಧಿಯ ಪ್ರಮಾಣ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 5a9bbc5..c198cb6 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"비밀번호를 확인하고 다시 시도하세요."</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"범위 내에 없음"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"자동으로 연결되지 않습니다."</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"인터넷에 연결되어 있지 않습니다."</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"인터넷에 연결되어 있지 않음"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g>(으)로 저장됨"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s을(를) 통해 자동으로 연결됨"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"네트워크 평가 제공업체를 통해 자동으로 연결됨"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s을(를) 통해 연결됨"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s을(를) 통해 사용 가능"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"인터넷을 사용하지 않고 연결됨"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"연결됨, 인터넷 사용 불가"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"액세스 포인트가 일시적으로 가득 참"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s을(를) 통해 연결됨"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s을(를) 통해 사용 가능"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP에 연결됨"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"파일 전송 서버에 연결되지 않았습니다."</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"입력 장치에 연결됨"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"인터넷 액세스를 위해 기기에 연결됨"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"로컬 인터넷 연결을 기기와 공유 중"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"인터넷 액세스에 사용"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"인터넷 액세스를 위해 기기에 연결됨"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"로컬 인터넷 연결을 기기와 공유 중"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"인터넷 액세스에 사용"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"지도에 사용"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM 액세스에 사용"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"미디어 오디오에 사용"</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 앱에서 4x MSAA 사용"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"사각형이 아닌 클립 작업 디버그"</string>
<string name="track_frame_time" msgid="6146354853663863443">"프로필 GPU 렌더링"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU 디버그 레이어 사용 설정"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"디버그 앱에 GPU 디버그 레이어 로드 허용"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"창 애니메이션 배율"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"전환 애니메이션 배율"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Animator 길이 배율"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 09edefe..0e2b8c0 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Сырсөздү текшерип, кайра аракет кылыңыз."</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Тейлөө аймагында эмес"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Автоматтык түрдө туташпайт"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Интернетке туташпай турат"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Интернетке туташпай турат"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> тарабынан сакталды"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s аркылуу автоматтык түрдө туташты"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Тармактардын рейтингинин автору аркылуу автоматтык түрдө туташты"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s аркылуу жеткиликтүү"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s аркылуу жеткиликтүү"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Туташып турат, Интернет жок"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Туташып турат, Интернет жок"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Туташуу түйүнү убактылуу толуп калды"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s аркылуу туташты"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s аркылуу иштейт"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP\'ка туташып турат"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Файл өткөрүү серверине туташкан жок"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Киргизүү түзмөгүнө туташты"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Интернетке мүмкүнчүлүк алуу үчүн түзмөккө туташты"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Жергиликтүү Интернет туташуусу түзмөк менен бөлүшүлүүдө"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Интернетке мүмкүнчүлүк алуу үчүн колдонулсун"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Интернетке мүмкүнчүлүк алуу үчүн түзмөккө туташты"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Жергиликтүү Интернет туташуусу түзмөк менен бөлүшүлүүдө"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Интернетке туташуу үчүн колдонулсун"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"MAP үчүн колдонуу"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM картаны пайдалануу үчүн колдонуу"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Медиа аудио үчүн колдонуу"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"PIN же код туура эмес болгондуктан <xliff:g id="DEVICE_NAME">%1$s</xliff:g> туташуу мүмкүн эмес."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> менен байланышуу мүмкүн эмес."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Жупташтырууну <xliff:g id="DEVICE_NAME">%1$s</xliff:g> четке какты."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Компьютер"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Гарнитура"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Телефон"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Сүрөт тартуучу түзмөк"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Кулакчын"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Дайындарды киргизүүчү сырткы түзмөк"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi өчүк."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi туташуусу жок."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wifi: бир таякча."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth аудио LDAC кодеги: Ойнотуу сапаты"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Bluetooth аудио LDAC кодегин тандаңыз:\nОйнотуу сапаты"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Трансляция: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"TLS аркылуу DNS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Эгер иштетилсе, DNS сервери TLS аркылуу 853-оюкчага аракет кылсын."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Купуя DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Купуя DNS режимин тандаңыз"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Өчүк"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Ийкемдүү"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Купуя DNS түйүндүн аталышы"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS түйүндүн аталышын киргизиңиз"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Зымсыз дисплейди сертификатто мүмкүнчүлүктөрүн көргөзүү"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fi Кармагычта Wi‑Fi протокол деңгээлин жогорулатуу жана ар бир SSID RSSI үчүн көрсөтүү."</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Иштетилсе, Wi-Fi байланышы үзүл-кесил болуп жатканда, Wi-Fi тармагы туташууну мобилдик Интернетке өжөрлүк менен өткөрүп берет"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 колдонмолорунда 4x MSAA иштетүү"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Түз бурчтук эмес кесүү операцияларын жөндөө"</string>
<string name="track_frame_time" msgid="6146354853663863443">"GPU иштетүү профайлы"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU мүчүлүштүктөрдү оңдоо катмарларын иштетүү"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"GPU мүчүлүштүктөрдү оңдоо катмарларын колдонмолордогу мүчүлүштүктөрдү оңдоо үчүн жүктөөгө уруксат берүү"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Терезе анимцснын шкаласы"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Өткөрүү анимацснн шкаласы"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Аниматор узактык масштабы"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index f1c92b07..32a001b 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"ກະລຸນາກວດສອບລະຫັດຜ່ານແລ້ວລອງໃໝ່ອີກຄັ້ງ"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"ບໍ່ຢູ່ໃນໄລຍະທີ່ເຊື່ອມຕໍ່ໄດ້"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"ຈະບໍ່ເຊື່ອມຕໍ່ອັດຕະໂນມັດ"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
<string name="saved_network" msgid="4352716707126620811">"ບັນທຶກໂດຍ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"ເຊື່ອມຕໍ່ຜ່ານທາງ %1$s ໂດຍອັດຕະໂນມັດ"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ເຊື່ອມຕໍ່ກັບອັດຕະໂນມັດແລ້ວຜ່ານຜູ້ໃຫ້ບໍລິການຄະແນນເຄືອຂ່າຍ"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"ເຊື່ອມຕໍ່ຜ່ານ %1$s ແລ້ວ"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"ມີໃຫ້ຜ່ານ %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"ເຊື່ອມຕໍ່ແລ້ວ, ບໍ່ມີອິນເຕີເນັດ"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ເຊື່ອມຕໍ່ແລ້ວ, ບໍ່ມີອິນເຕີເນັດ"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ຈຸດການເຂົ້າເຖິງເຕັມຊົ່ວຄາວ"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"ເຊື່ອມຕໍ່ຜ່ານ %1$s ແລ້ວ"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"ໃຊ້ໄດ້ຜ່ານ %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"ເຊື່ອມຕໍ່ກັບ SAP ແລ້ວ"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ບໍ່ໄດ້ເຊື່ອມຕໍ່ຫາເຊີບເວີໂອນຍ້າຍໄຟລ໌"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ເຊື່ອມຕໍ່ກັບອຸປະກອນປ້ອນຂໍ້ມູນແລ້ວ"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"ເຊື່ອມຕໍ່ກັບອຸປະກອນເພື່ອເຂົ້າເຖິງອິນເຕີເນັດແລ້ວ"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ກຳລັງແບ່ງປັນການເຊື່ອມຕໍ່ອິນເຕີເນັດກັບອຸປະກອນ"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ໃຊ້ເພື່ອເຂົ້າອິນເຕີເນັດ"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"ເຊື່ອມຕໍ່ກັບອຸປະກອນເພື່ອເຂົ້າເຖິງອິນເຕີເນັດແລ້ວ"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"ກຳລັງແບ່ງປັນການເຊື່ອມຕໍ່ອິນເຕີເນັດກັບອຸປະກອນ"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"ໃຊ້ເພື່ອເຂົ້າອິນເຕີເນັດ"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"ໃຊ້ສຳລັບແຜນທີ່"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"ການໃຊ້ສໍາລັບການເຂົ້າເຖິງ SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"ໃຊ້ສຳລັບສື່ດ້ານສຽງ"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"ບໍ່ສາມາດຈັບຄູ່ກັບ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ໄດ້ ເພາະ PIN ຫຼື passkey ບໍ່ຖືກຕ້ອງ."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"ບໍ່ສາມາດຕິດຕໍ່ສື່ສານກັບ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ໄດ້."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"ການຈັບຄູ່ຖືກປະຕິເສດໂດຍ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"ຄອມພິວເຕີ"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"ຊຸດຫູຟັງ"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"ໂທລະສັບ"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"ຮູບພາບ"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"ຫູຟັງ"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"ອຸປະກອນພ່ວງອິນພຸດ"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"WiFi ປິດຢູ່."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"ຕັດການເຊື່ອມຕໍ່ Wi-Fi ແລ້ວ."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"ສັນຍານ Wi-Fi ນຶ່ງຂີດ."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth Audio LDAC Codec: Playback Quality"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Select Bluetooth Audio LDAC Codec:\nPlayback Quality"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS ຜ່ານ TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"ຫາກເປີດໃຊ້, ລະບົບຈະພະຍາຍາມໃຊ້ DNS ຜ່ານ TLS ຢູ່ຜອດ 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS ສ່ວນຕົວ"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"ເລືອກໂໝດ DNS ສ່ວນຕົວ"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"ປິດ"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"ກ່ຽວກັບໂອກາດ"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"ຊື່ໂຮສຜູ້ໃຫ້ບໍລິການ DNS ສ່ວນຕົວ"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"ລະບຸຊື່ໂຮສຂອງຜູ້ໃຫ້ບໍລິການ DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ສະແດງໂຕເລືອກສຳລັບການສະແດງການຮັບຮອງລະບົບໄຮ້ສາຍ"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"ເພີ່ມລະດັບການເກັບປະຫວັດ Wi‑Fi, ສະແດງຕໍ່ SSID RSSI ໃນ Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"ເມື່ອເປີດໃຊ້ແລ້ວ, Wi-Fi ຈະສົ່ງຜ່ານການເຊື່ອມຕໍ່ຂໍ້ມູນໄປຫາເຄືອຂ່າຍມືຖືເມື່ອສັນຍານ Wi-Fi ອ່ອນ"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"ເປິດໃຊ້ 4x MSAA ໃນແອັບຯ OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"ດີບັ໊ກການເຮັດວຽກຂອງຄລິບທີ່ບໍ່ແມ່ນສີ່ຫຼ່ຽມ"</string>
<string name="track_frame_time" msgid="6146354853663863443">"ສະແດງຜົນ GPU ຕາມໂປຣໄຟລ໌"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"ເປີດໃຊ້ຊັ້ນຂໍ້ມູນດີບັກ GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"ອະນຸຍາດການໂຫລດຊັ້ນຂໍ້ມູນດີບັກ GPU ສຳລັບແອັບດີບັກ"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"ຂະໜາດອະນິເມຊັນ"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"ຂະໜາດສະລັບອະນິເມຊັນ"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"ໄລຍະເວລາອະນິເມຊັນ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index f888504..0e49f5be 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Patikrinkite slaptažodį ir bandykite dar kartą"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Ne diapazone"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nebus automatiškai prisijungiama"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Nėra interneto ryšio"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Nėra interneto ryšio"</string>
<string name="saved_network" msgid="4352716707126620811">"Išsaugojo <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatiškai prisijungta naudojant „%1$s“"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatiškai prisijungta naudojant tinklo įvertinimo paslaugos teikėjo paslaugomis"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Prisijungta naudojant „%1$s“"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Pasiekiama naudojant „%1$s“"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Prisijungta, nėra interneto"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Prisijungta, nėra interneto"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Prieigos taškas laikinai visiškai užimtas"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Prisijungta naudojant „%1$s“"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Pasiekiama naudojant „%1$s“"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Prisijungta prie SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Neprijungta prie failų perkėlimo serverio"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Prisijungta prie įvesties įrenginio."</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Pr. prie įr., kad gaut. pr. prie int."</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Bendr. vt. int. ryš. su įr."</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Naudoti interneto prieigai"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Prisij. prie įr. norint pasiekti inter."</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Viet. intern. ryšio bendrinimas su įrenginiu"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Naudoti prisijungiant prie interneto"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Naudoti žemėlapyje"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Naudoti SIM prieigai"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Naudoti medijos garsui"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nepavyko susieti su „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“ dėl netinkamo PIN kodo ar prieigos rakto."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Nepavyksta užmegzti ryšio su „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Susiejimą atmetė <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Kompiuteris"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Ausinės"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefonas"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Vaizdavimo įrenginys"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Ausinės"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Išorinis įvesties įrenginys"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"„Wi-Fi“ išjungtas."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"„Wi-Fi“ atjungtas."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Viena „Wi-Fi“ signalo juosta."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"„Bluetooth“ garso LDAC kodekas: atkūrimo kokybė"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Pasirinkite „Bluetooth“ garso LDAC kodeką:\natkūrimo kokybė"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Srautinis perdavimas: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS naudojant TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Jei parinktis įgalinta, bandykite pateikti DNS užklausą naudojant TLS 853 prievadu."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privatus DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Pasirinkite privataus DNS režimą"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Išjungta"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunistinis"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Privataus DNS teikėjo prieglobos serverio pavadinimas"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Įveskite DNS teikėjo prieglobos serverio pavadinimą"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Rodyti belaidžio rodymo sertifikavimo parinktis"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Padidinti „Wi‑Fi“ įrašymo į žurnalą lygį, rodyti SSID RSSI „Wi-Fi“ rinkiklyje"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Jei ši parinktis įgalinta, „Wi‑Fi“ agresyviau perduos duomenų ryšiu į mobiliojo ryšio tinklą, kai „Wi‑Fi“ signalas silpnas"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Įgalinti 4x MSAA „OpenGL ES 2.0“ programose"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Derinti ne stačiakampio klipo operacijas"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Profiliuotas GPU atvaizd."</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Įg. graf. proc. der. sl."</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Leisti įkelti graf. proc. der. sluoks. der. progr."</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Lango animacijos mast."</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Animuoto perėjimo mast."</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Animator. trukmės skalė"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index dbe13b5..fd9d60c 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Pārbaudiet paroli un mēģiniet vēlreiz."</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Nav diapazona ietvaros"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Savienojums netiks izveidots automātiski"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Nav piekļuves internetam"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Nav piekļuves internetam"</string>
<string name="saved_network" msgid="4352716707126620811">"Saglabāja: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Automātiski savienots, izmantojot %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automātiski izveidots savienojums, izmantojot tīkla vērtējuma sniedzēju"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Savienots, izmantojot %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Pieejams, izmantojot %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Savienots, nav piekļuves internetam"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Savienojums izveidots, nav piekļuves internetam"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Piekļuves punkts īslaicīgi ir pilns"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Savienojums izveidots, izmantojot %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Pieejams, izmantojot %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Savienots ar SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nav savienots ar failu pārsūtīšanas serveri"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Izveidots savienojums ar ievades ierīci"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Savien. ar ier., lai nodr. int. piekļ."</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Tiek kopliet. lok. intern. savien. ar ierīci"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Izmantot, lai piekļūtu internetam"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Savien. ar ier., lai nodr. int. piekļ."</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Tiek kopliet. lok. intern. savien. ar ierīci"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Izmantot, lai piekļūtu internetam"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Lietot kartei"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Izmantot, lai piekļūtu SIM kartei"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Izmantot multivides skaņai"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nevarēja savienot pārī ar ierīci <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, jo tika ievadīts nepareizs PIN kods vai nepareiza ieejas atslēga."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Nevar sazināties ar ierīci <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> noraidīja pāra izveidi."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Dators"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Austiņas ar mikrofonu"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Tālrunis"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Attēlu apstrādes ierīce"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Austiņas"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Ievades ierīce"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi savienojums izslēgts"</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi savienojums pārtraukts"</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi: viena josla"</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth audio LDAC kodeks: atskaņošanas kvalitāte"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Atlasīt Bluetooth audio LDAC kodeku:\natskaņošanas kvalitāte"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Straumēšana: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS, izmantojot TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Ja opcija ir iespējota, tiek mēģināts pieprasīt DNS, izmantojot TLS portā 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privāts DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Atlasiet privāta DNS režīmu"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Izslēgts"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportūnistisks"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Privātā DNS pakalpojumu sniedzēja saimniekdatora nosaukums"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Ievadiet DNS pakalpojumu sniedzēja saimniekdatora nosaukumu"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Rādīt bezvadu attēlošanas sertifikācijas iespējas"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Palieliniet Wi‑Fi reģistrēšanas līmeni; rādīt katram SSID RSSI Wi‑Fi atlasītājā."</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Ja opcija ir iespējota un Wi‑Fi signāls ir vājš, datu savienojuma pāreja no Wi-Fi uz mobilo tīklu tiks veikta agresīvāk."</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Iespējot 4x MSAA OpenGL ES 2.0 lietotnēs"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Atkļūdot darbības daļā, kas nav taisnstūris."</string>
<string name="track_frame_time" msgid="6146354853663863443">"Profila GPU atveide"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Iesp. GPU atkļūd. slāņus"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Atļaut GPU atkļūd. slāņu ielādi atkļūd. lietotnēm"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Loga animācijas mērogs"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Pārejas animācijas mērogs"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Animācijas ilguma mērogs"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 0ebb44d..85cd020 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Проверете ја лозинката и обидете се повторно"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Надвор од опсег"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Не може да се поврзе автоматски"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Нема пристап до Интернет"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Нема пристап до интернет"</string>
<string name="saved_network" msgid="4352716707126620811">"Зачувано од <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Автоматски поврзано преку %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Автоматски поврзано преку оператор за оценување мрежа"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Поврзано преку %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Достапно преку %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Поврзана, нема интернет"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Поврзана, нема интернет"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Пристапната точка привремено е преоптоварена"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Поврзано преку %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Достапно преку %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Поврзано со SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Не е поврзан со сервер за пренос на датотеки"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Поврзан со влезен уред"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Поврзан со уред за пристап на интернет"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Споделување локална конекција на интернет со уред"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Користи за пристап на интернет"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Повр. со уред за интернет"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Се спод. интернет-врска"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Користи за пристап до интернет"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Користи за карта"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Користете се пристап до SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Користи за аудио на медиуми"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Не можеше да се спари со <xliff:g id="DEVICE_NAME">%1$s</xliff:g> поради погрешен PIN или лозинка."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Не може да комуницира со <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Спарувањето е одбиено од <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Компјутер"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Слушалки"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Телефон"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Слики"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Слушалка"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Периферен влез"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi е исклучено."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi е исклучено."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Една црта на Wi-Fi."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Кодек за LDAC-аудио преку Bluetooth: квалитет на репродукција"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Изберете кодек за LDAC-аудио преку Bluetooth:\nКвалитет на репродукција"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Емитување: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS преку TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Ако е овозможено, обидете се со DNS преку TLS на портата 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Приватен DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Изберете режим на приватен DNS"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Исклучено"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Опортунистички"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Име на хост на оператор на приватен DNS"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Внесете име на хост на операторот на DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Покажи ги опциите за безжичен приказ на сертификат"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Зголеми Wi‑Fi ниво на пријавување, прикажи по SSID RSSI во Wi‑Fi бирач"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Кога е овозможено, Wi-Fi ќе биде поагресивна при предавање на интернет-врската на мобилната мрежа при слаб сигнал на Wi-Fi"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Овозможи 4x MSAA за апликации OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Отстрани грешка на неправоаголни клип операции"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Прикажување пофил на GPU"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Овозм. отстр. греш. на GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Дозволи отстр. греш. на GPU за поправање апликации"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Опсег на аним. на прозор."</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Опсег на преодна анимац."</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Скала за времетраење на аниматор"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index a96fbcf..77b58cf 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"പാസ്വേഡ് പരിശോധിച്ച് വീണ്ടും ശ്രമിക്കുക"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"പരിധിയിലില്ല"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"സ്വയമേവ കണക്റ്റുചെയ്യില്ല"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"ഇന്റർനെറ്റ് ആക്സസ്സ് ഇല്ല"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"ഇന്റർനെറ്റ് ആക്സസ് ഇല്ല"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> സംരക്ഷിച്ചത്"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s വഴി സ്വയമേവ ബന്ധിപ്പിച്ചു"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"നെറ്റ്വർക്ക് റേറ്റിംഗ് ദാതാവുമായി സ്വയം കണക്റ്റുചെയ്തു"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s വഴി ബന്ധിപ്പിച്ചു"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s വഴി ലഭ്യം"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"കണക്റ്റുചെയ്തിരിക്കുന്നു, ഇന്റർനെറ്റില്ല"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"കണക്റ്റ് ചെയ്തു, ഇന്റർനെറ്റ് ഇല്ല"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ആക്സസ് പോയിന്റ് താൽക്കാലികമായി നിറഞ്ഞിരിക്കുന്നു"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s വഴി ബന്ധിപ്പിച്ചു"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s വഴി ലഭ്യം"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP-യിലേക്ക് ബന്ധിപ്പിച്ചു"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ഫയൽ കൈമാറ്റ സെർവറിൽ കണക്റ്റുചെയ്തിട്ടില്ല"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ഇൻപുട്ട് ഉപകരണത്തിൽ കണക്റ്റുചെയ്തു"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"ഇന്റർനെറ്റ് ആക്സസ്സിനായി ഉപകരണത്തിൽ കണക്റ്റുചെയ്തു"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ഉപകരണവുമായി പ്രദേശിക ഇന്റർനെറ്റ് കണക്ഷൻ പങ്കിടുന്നു"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ഇന്റർനെറ്റ് ആക്സസ്സിനായി ഉപയോഗിക്കുന്നു"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"ഇന്റർനെറ്റ് ആക്സസിനായി ഉപകരണത്തിൽ കണക്റ്റ് ചെയ്തു"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"ഉപകരണവുമായി ലോക്കൽ ഇന്റർനെറ്റ് കണക്ഷൻ പങ്കിടുന്നു"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"ഇന്റർനെറ്റ് ആക്സസിനായി ഉപയോഗിക്കുന്നു"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"മാപ്പിനായി ഉപയോഗിക്കുക"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM ആക്സസിന് ഉപയോഗിക്കുക"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"മീഡിയ ഓഡിയോയ്ക്കായി ഉപയോഗിക്കുക"</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 അപ്ലിക്കേഷനുകളിൽ 4x MSAA പ്രവർത്തനക്ഷമമാക്കുക"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"ചതുരാകൃതിയിലല്ലാത്ത ക്ലിപ്പ്പ്രവർത്തനം ഡീബഗുചെയ്യൂ"</string>
<string name="track_frame_time" msgid="6146354853663863443">"പ്രൊഫൈൽ GPU റെൻഡർചെയ്യൽ"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU ഡീബഗ് ലെയറുകൾ പ്രവർത്തനക്ഷമമാക്കൂ"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"ഡീബഗ് ആപ്പുകൾക്കായി GPU ഡീബഗ് ലെയറുകൾ ലോഡ് ചെയ്യാൻ അനുവദിക്കുക"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"വിൻഡോ ആനിമേഷൻ സ്കെയിൽ"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"സംക്രമണ ആനിമേഷൻ സ്കെയിൽ"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"ആനിമേറ്റർ ദൈർഘ്യ സ്കെയിൽ"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 0990ecf..3c6690c 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Нууц үгийг шалгаад дахин оролдоно уу"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Хүрээнд байхгүй"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Автоматаар холбогдохгүй"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Интернэт холболт алга"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Интернет хандалт алга"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> хадгалсан"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s-р автоматаар холбогдсон"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Сүлжээний үнэлгээ үзүүлэгчээр автоматаар холбогдох"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s-р холбогдсон"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s-р боломжтой"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Холбогдсон, интернэт байхгүй байна"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Холбогдсон хэдий ч интернет алга"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Хандах цэг түр хугацаанд дүүрсэн байна"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s-р холбогдсон"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s-р боломжтой"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP-д холбогдсон"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Файл дамжуулах серверт холбогдоогүй"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Оруулах төхөөрөмжтэй холбогдсон"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Интернетэд хандахын тулд төхөөрөмжтэй холбогдсон"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Төхөөрөмжтэй локал Интернет холболтыг хуваалцаж байна"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Интернет хандалтанд ашиглах"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Интернетэд хандахын тулд төхөөрөмжтэй холбогдсон"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Төхөөрөмжтэй дотоод интернет холболтыг хуваалцаж байна"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Интернет хандалтад ашиглах"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Газрын зурагт ашиглах"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM хандалтад ашиглах"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Медиа аудиод ашиглах"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Буруу PIN эсхүл дамжих түлхүүрээс шалтгаалан <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-тай хослуулж чадсангүй."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>-тай холбоо барих боломжгүй."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Хослуулахаас <xliff:g id="DEVICE_NAME">%1$s</xliff:g> татгалзсан."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Компьютер"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Чихэвч"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Утас"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Зураглал"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Чихэвч"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Нэмэлт оролт"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi унтраалттай байна."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi холбогдоогүй байна."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wifi сүлжээний дохио нэг баганатай байна."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth Аудио LDAC Кодлогч: Тоглуулагчийн чанар"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Bluetooth Аудио LDAC Кодлогч сонгох:\nТоглуулагчийн чанар"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Дамжуулж байна: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"TLS дээрх DNS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Идэвхжүүлсэн тохиолдолд TLS-р DNS-г 853-р портод оролдоно уу."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Хувийн DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Хувийн DNS Горимыг сонгох"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Унтраалттай"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Оппортунист үзэлтэн"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Хувийн DNS-н үйлчилгээ үзүүлэгчийн хостын нэр"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS-н үйлчилгээ үзүүлэгчийн хостын нэрийг оруулах"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Утасгүй дэлгэцийн сертификатын сонголтыг харуулах"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi лог-н түвшинг нэмэгдүүлэх, Wi‑Fi Сонгогч дээрх SSID-д ногдох RSSI-г харуулах"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Идэвхжүүлсэн үед Wi‑Fi холболт сул байх үед дата холболтыг мобайлд шилжүүлэхэд илүү идэвхтэй байх болно"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 апп-уудад 4x MSAA-г идэвхжүүлэх"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Тэгш өнцөгт бус клипийн үйлдлүүдийн согогийг засах"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Профайл GPU гаргах"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU дебаг хийх давхаргыг идэвхжүүлэх"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Дебаг хийх аппад GPU дебаг хийх давхарга ачааллахыг зөвшөөрөх"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Цонхны дүрс амилуулалтын далайц"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Шилжилтийн дүрс амилуулалтын далайц"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Дүрс амилуулалт үргэлжлэх далайц"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 74734a0..bb0a337 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -33,15 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"पासवर्ड तपासा आणि पुन्हा प्रयत्न करा"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"परिक्षेत्रामध्ये नाही"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"स्वयंचलितपणे कनेक्ट करणार नाही"</string>
- <!-- no translation found for wifi_no_internet (4663834955626848401) -->
- <skip />
+ <string name="wifi_no_internet" msgid="4663834955626848401">"इंटरनेट अॅक्सेस नाही"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> द्वारे सेव्ह केले"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s द्वारे स्वयंचलितपणे कनेक्ट केले"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"नेटवर्क रेटिंग प्रदात्याद्वारे स्वयंचलितपणे कनेक्ट केले"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s द्वारे कनेक्ट केले"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s द्वारे उपलब्ध"</string>
- <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"कनेक्ट केले, इंटरनेट नाही"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"अॅक्सेस पॉइंट तात्पुरते भरलेले"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s ने कनेक्ट केले"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s ने उपलब्ध"</string>
@@ -86,8 +84,7 @@
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"इनपुट डिव्हाइसवर कनेक्ट केले"</string>
<string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"इंटरनेट अॅक्सेससाठी डिव्हाइसशी कनेक्ट केले"</string>
<string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"डिव्हाइससह स्थानिक इंटरनेट कनेक्शन शेअर करत आहे"</string>
- <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
- <skip />
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"इंटरनेट अॅक्सेस करण्यासाठी वापरा"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"नकाशासाठी वापरा"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM प्रवेशासाठी वापरा"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"मीडिया ऑडिओसाठी वापरा"</string>
@@ -100,7 +97,7 @@
<string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"कनेक्ट केल्यावर पेअरींग तुमचे संपर्क आणि कॉल इतिहास यामध्ये अॅक्सेस देते."</string>
<string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> शी जोडू शकलो नाही."</string>
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"अयोग्य पिन किंवा पासकीमुळे <xliff:g id="DEVICE_NAME">%1$s</xliff:g> सह जोडू शकलो नाही."</string>
- <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> शी संप्रेषण करू शकत नाही."</string>
+ <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> शी संवाद प्रस्थापित करू शकत नाही."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> द्वारे पेअरींग नाकारले."</string>
<string name="bluetooth_talkback_computer" msgid="4875089335641234463">"संगणक"</string>
<string name="bluetooth_talkback_headset" msgid="5140152177885220949">"हेडसेट"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 857093a..aa94b7c 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Semak kata laluan, kemudian cuba lagi"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Tidak dalam liputan"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Tidak akan menyambung secara automatik"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Tiada akses Internet"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Tiada akses Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Diselamatkan oleh <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Disambungkan secara automatik melalui %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Disambungkan secara automatik melalui pembekal penilaian rangkaian"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Disambungkan melalui %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Tersedia melalui %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Disambungkan, tiada Internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Disambungkan, tiada Internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Titik akses penuh buat sementara waktu"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Disambungkan melalui %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Tersedia melalui %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Disambungkan ke SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Tidak bersambung kepada pelayan pemindahan fail"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Disambungkan ke peranti input"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Sbg ke pranti utk aks Int"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Kgsi sbgn Int dgn peranti"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Gunakan untuk akses Internet"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Dismbgkn ke peranti utk akses Internet"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Berkongsi smbgn Internet setempat dgn peranti"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Gunakan untuk akses Internet"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Gunakan untuk peta"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Gunakan untuk akses SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Gunakan untuk audio media"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Tidak dapat berpasangan dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> kerana PIN atau kunci laluan yang salah."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Tidak boleh berkomunikasi dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Pasangan ditolak oleh <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Komputer"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Set Kepala"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Pengimejan"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Fon kepala"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Persisian Input"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi dimatikan."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi diputuskan sambungannya."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi satu bar."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codec LDAC Audio Bluetooth: Kualiti Main Balik"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Pilih Codec LDAC Audio Bluetooth:\nKualiti Main Balik"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Penstriman: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS di atas TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Jika di dayakan, cuba DNS di atas TLS pada port 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS Peribadi"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Pilih Mod DNS Peribadi"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Mati"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunistik"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Nama hos pembekal DNS peribadi"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Masukkan nama hos pembekal DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Tunjukkan pilihan untuk pensijilan paparan wayarles"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Tingkatkan tahap pengelogan Wi-Fi, tunjuk setiap SSID RSSI dalam Pemilih Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Apabila didayakan, Wi-Fi akan menjadi lebih agresif dalam menyerahkan sambungan data ke mudah alih, apabila isyarat Wi-Fi rendah"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Dayakan 4x MSAA dalam apl OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Nyahpepijat operasi keratan bukan segi empat tepat"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Pemaparan GPU profil"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Dayakan lpsn nyhppjat GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Bnrkn pemuatan lpsn nyhppjt GPU utk apl pnyhppjtn"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Skala animasi tetingkap"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Skala animasi peralihan"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Skala tempoh juruanimasi"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index d0fce81..57f6c6f 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -33,15 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"စကားဝှက်ကို စစ်ဆေးပြီး ထပ်လုပ်ကြည့်ပါ"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"စက်ကွင်းထဲတွင် မဟုတ်ပါ"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"အလိုအလျောက်ချိတ်ဆက်မည်မဟုတ်ပါ"</string>
- <!-- no translation found for wifi_no_internet (4663834955626848401) -->
- <skip />
+ <string name="wifi_no_internet" msgid="4663834955626848401">"အင်တာနက် ချိတ်ဆက်မှု မရှိပါ"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> မှသိမ်းဆည်းခဲ့သည်"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s မှတစ်ဆင့် အလိုအလျောက် ချိတ်ဆက်ထားပါသည်"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ကွန်ရက်အဆင့်သတ်မှတ်ပေးသူ မှတစ်ဆင့် အလိုအလျောက် ချိတ်ဆက်ထားပါသည်"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s မှတစ်ဆင့် ချိတ်ဆက်ထားသည်"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s မှတစ်ဆင့်ရနိုင်သည်"</string>
- <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ချိတ်ဆက်ထားသည်၊ အင်တာနက်မရှိ"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ကွန်ရက်ချိတ်ဆက်မှု ယာယီပြည့်နေသည်"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s မှတစ်ဆင့် ချိတ်ဆက်ထားသည်"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s မှတစ်ဆင့် ရနိုင်သည်"</string>
@@ -86,8 +84,7 @@
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ထည့်သွင်းထားသောစက်ကို ချိတ်ဆက်မည်"</string>
<string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"အင်တာနက် ချိတ်ထားသည်"</string>
<string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"စက်နှင့် အင်တာနက်မျှဝေရန်"</string>
- <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
- <skip />
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"အင်တာနက်ချိတ်ဆက်ရန် အသုံးပြုသည်"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"မြေပုံအတွက်သုံးရန်"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM အသုံးပြုမှုအတွက် အသုံးပြုမည်"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"မီဒီယာအသံအတွက်အသုံးပြုရန်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index f88df54..1cabc5c 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Sjekk passordet og prøv igjen"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Utenfor område"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Kobler ikke til automatisk"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Ingen Internett-tilgang"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Ingen Internett-tilgang"</string>
<string name="saved_network" msgid="4352716707126620811">"Lagret av <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatisk tilkoblet via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatisk tilkoblet via leverandør av nettverksvurdering"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Tilkoblet via %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Tilgjengelig via %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Tilkoblet – ingen Internett-forbindelse"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Tilkoblet – ingen Internett-tilgang"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Tilgangspunktet er midlertidig fullt"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Tilkoblet via %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Tilgjengelig via %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Koblet til SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Ikke koblet til tjener for filoverføring"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Koblet til inndataenhet"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Koblet til enhet for Internett-tilgang"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Deler lokal Internett-tilkobling med enhet"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Bruk for Internett-tilgang"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Koblet til enhet for Internett-tilgang"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Deler lokal Internett-tilkobling med enhet"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Bruk for Internett-tilgang"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Bruk for kart"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Bruk for tilgang til SIM-kortet"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Bruk for medielyd"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Kan ikke koble til <xliff:g id="DEVICE_NAME">%1$s</xliff:g> på grunn av feil personlig kode eller passord."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Kan ikke kommunisere med <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> avslo paring."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Datamaskin"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Hodetelefoner"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Bildefremviser"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Øretelefoner"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Inndata fra ytre utstyrsenheter"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi er av."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi er frakoblet."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi-signal med én stolpe."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"LDAC-kodek for Bluetooth-lyd: Avspillingskvalitet"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Velg LDAC-kodek for Bluetooth-lyd:\nAvspillingskvalitet"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Strømming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS over TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Hvis det er slått på, forsøk DNS over TLS på port 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privat DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Velg Privat DNS-modus"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Av"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistisk"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Vertsnavn for privat DNS-leverandør"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Skriv inn vertsnavnet til DNS-leverandøren"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Vis alternativer for sertifisering av trådløs skjerm"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Øk Wi-Fi-loggenivå – vis per SSID RSSI i Wi-Fi-velgeren"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Hvis dette slås på, overfører Wi-Fi-nettverket datatilkoblingen til mobil mer aggressivt når Wi-Fi-signalet er svakt"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Slå på 4x MSAA i OpenGL ES 2.0-apper"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Feilsøk ikke-rektangulær klipping"</string>
<string name="track_frame_time" msgid="6146354853663863443">"GPU-gjengivelse av profil"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Slå på GPU-feilsøkingslag"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Tillat GPU-feilsøkingslag for feilsøkingsapper"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Animasjonsskala for vindu"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Overgangsanimasjonsskala"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Varighetsskala animasjon"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 172fed1..f5f2269 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"पासवर्ड जाँच गरेर फेरि प्रयास गर्नुहोस्"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"दायराभित्र छैन"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"स्वतः जडान हुने छैन"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"इन्टरनेट माथिको पहुँच छैन"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"इन्टरनेटमाथिको पहुँच छैन"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> द्वारा सुरक्षित गरियो"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s मार्फत् स्वतः जडान गरिएको"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"नेटवर्कको दर्जा प्रदायक मार्फत स्वत: जडान गरिएको"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s मार्फत जडित"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s मार्फत उपलब्ध"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"जडित, इन्टरनेट चलेको छैन"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"जडान गरियो तर इन्टरनेट छैन"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"पहुँचसम्बन्धी स्थान अस्थायी रूपमा भरिएको छ"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s मार्फत जडान गरियो"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s मार्फत उपलब्ध"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP मा जडित"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"फाइल ट्रान्सफर सर्भरसँग जडान गरिएको छैन"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"इनपुट उपकरणसँग जोडिएको छ"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"इन्टरनेट पहुँचका लागि उपकरणसँग जडित"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"उपकरणसँग स्थानीय इन्टरनेट जडान साझेदारी गर्दै"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"इन्टर्नेट पहुँचका लागि प्रयोग गर्नुहोस्"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"इन्टरनेटमाथिको पहुँचका लागि यन्त्रमा जडान गरियो"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"यन्त्रसँग स्थानीय इन्टरनेट जडान साझा गर्दै"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"इन्टरनेटमाथि पहुँच राख्न प्रयोग गर्नुहोस्"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"नक्साको लागि प्रयोग गर्नुहोस्"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM मा पहुँचका लागि प्रयोग गर्नुहोस्"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"मिडिया अडियोका लागि प्रयोग गर्नुहोस्"</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES २.० अनुप्रयोगमा ४x MSAA सक्षम पार्नुहोस्"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"गैर आयातकर क्लिप कार्यहरू डिबग गर्नुहोस्"</string>
<string name="track_frame_time" msgid="6146354853663863443">"प्रोफाइल GPU रेन्डर गर्दै"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU का डिबग तहहरूलाई सक्षम पार्नुहोस्"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"डिबगसम्बन्धी अनुप्रयोगहरूका लागि GPU का डिबग तहहरूलाई लोड गर्न दिनुहोस्"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"विन्डो सजीविकरण स्केल"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"संक्रमण सजीविकरण मापन"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"सजीविकरण अवधि मापन"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 38853f0..fe17c1d 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Controleer het wachtwoord en probeer het opnieuw"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Niet binnen bereik"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Er wordt niet automatisch verbinding gemaakt"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Geen internettoegang"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Geen internettoegang"</string>
<string name="saved_network" msgid="4352716707126620811">"Opgeslagen door <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatisch verbonden via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatisch verbonden via provider van netwerkbeoordelingen"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Verbonden via %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Beschikbaar via %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Verbonden, geen internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Verbonden, geen internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Toegangspunt tijdelijk vol"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Verbonden via %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Beschikbaar via %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Verbonden via SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Niet verbonden met server voor bestandsoverdracht"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Verbonden met invoerapparaat"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Verbonden met apparaat voor internet"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Lokale internetverbinding delen met apparaat"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Gebruik voor internettoegang"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Verbonden met apparaat voor internettoegang"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Lokale internetverbinding delen met apparaat"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Gebruik voor internettoegang"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Gebruiken voor kaart"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Gebruiken voor sim-toegang"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Gebruiken voor audio van medium"</string>
@@ -237,7 +237,7 @@
<string name="allow_mock_location" msgid="2787962564578664888">"Neplocaties toestaan"</string>
<string name="allow_mock_location_summary" msgid="317615105156345626">"Neplocaties toestaan"</string>
<string name="debug_view_attributes" msgid="6485448367803310384">"Inspectie van weergavekenmerk inschakelen"</string>
- <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Mobiele gegevens altijd actief houden, ook als wifi actief is (voor sneller schakelen tussen netwerken)."</string>
+ <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"mobiele data altijd actief houden, ook als wifi actief is (voor sneller schakelen tussen netwerken)."</string>
<string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Hardwareversnelling voor tethering gebruiken indien beschikbaar"</string>
<string name="adb_warning_title" msgid="6234463310896563253">"USB-foutopsporing toestaan?"</string>
<string name="adb_warning_message" msgid="7316799925425402244">"USB-foutopsporing is alleen bedoeld voor ontwikkeldoeleinden. Het kan worden gebruikt om gegevens te kopiëren tussen je computer en je apparaat, apps zonder melding op je apparaat te installeren en loggegevens te lezen."</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"4x MSAA inschakelen in OpenGL ES 2.0-apps"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Fouten met niet-rechthoekige bijsnijdbewerkingen opsporen"</string>
<string name="track_frame_time" msgid="6146354853663863443">"GPU-rendering van profiel"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU-foutopsporingslagen inschakelen"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Laden van GPU-foutopsporingslagen toestaan voor foutopsporingsapps"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Vensteranimatieschaal"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Overgangsanimatieschaal"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Duur van animatieschaal"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index be4fa8d..c791107 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"ਪਾਸਵਰਡ ਦੀ ਜਾਂਚ ਕਰੋ ਅਤੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"ਰੇਂਜ ਵਿੱਚ ਨਹੀਂ ਹੈ"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾਵੇਗਾ"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"ਕੋਈ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"ਕੋਈ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ਵੱਲੋਂ ਸੁਰੱਖਿਅਤ ਕੀਤਾ"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s ਰਾਹੀਂ ਆਪਣੇ-ਆਪ ਕਨੈਕਟ ਹੋਇਆ"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ਨੈੱਟਵਰਕ ਰੇਟਿੰਗ ਪ੍ਰਦਾਨਕ ਰਾਹੀਂ ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਕਨੈਕਟ ਹੋਇਆ"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s ਰਾਹੀਂ ਉਪਲਬਧ"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"ਕਨੈਕਟ ਕੀਤਾ, ਕੋਈ ਇੰਟਰਨੈੱਟ ਨਹੀਂ"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ਕਨੈਕਟ ਕੀਤਾ, ਕੋਈ ਇੰਟਰਨੈੱਟ ਨਹੀਂ"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ਐਕਸੈੱਸ ਪੁਆਇੰਟ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਸੰਪੂਰਨ ਰੁਝੇਂਵੇਂ ਵਿੱਚ ਹੈ"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s ਰਾਹੀਂ ਉਪਲਬਧ"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ਫਾਈਲ ਟ੍ਰਾਂਸਫ਼ਰ ਸਰਵਰ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ਇਨਪੁੱਟ ਡੀਵਾਈਸ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਲਈ ਡੀਵਾਈਸ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ਡੀਵਾਈਸ ਨਾਲ ਸਥਾਨਕ ਇੰਟਰਨੈੱਟ ਕਨੈਕਸ਼ਨ ਸਾਂਝਾ ਕਰ ਰਿਹਾ ਹੈ"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਲਈ ਵਰਤੋ"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਲਈ ਡੀਵਾਈਸ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"ਡੀਵਾਈਸ ਨਾਲ ਸਥਾਨਕ ਇੰਟਰਨੈੱਟ ਕਨੈਕਸ਼ਨ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਲਈ ਵਰਤੋ"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"ਨਕਸ਼ੇ ਲਈ ਵਰਤੋ"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"ਸਿਮ ਪਹੁੰਚ ਲਈ ਵਰਤੋ"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"ਮੀਡੀਆ ਆਡੀਓ ਲਈ ਵਰਤੋ"</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 ਐਪਾਂ ਵਿੱਚ 4x MSAA ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"ਗੈਰ-ਆਇਤਾਕਾਰ ਕਲਿੱਪ ਓਪਰੇਸ਼ਨ ਡੀਬੱਗ ਕਰੋ"</string>
<string name="track_frame_time" msgid="6146354853663863443">"ਪ੍ਰੋਫਾਈਲ GPU ਰੈਂਡਰਿੰਗ"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU ਡੀਬੱਗ ਲੇਅਰਾਂ ਚਾਲੂ ਕਰੋ"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"ਡੀਬੱਗ ਐਪਾਂ ਲਈ GPU ਡੀਬੱਗ ਲੇਅਰਾਂ ਨੂੰ ਲੋਡ ਹੋਣ ਦਿਓ"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"ਵਿੰਡੋ ਐਨੀਮੇਸ਼ਨ ਸਕੇਲ"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"ਟ੍ਰਾਂਜਿਸ਼ਨ ਐਨੀਮੇਸ਼ਨ ਸਕੇਲ"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"ਐਨੀਮੇਟਰ ਮਿਆਦ ਸਕੇਲ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 51c8505..3c0cf9e 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Sprawdź hasło i spróbuj ponownie"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Poza zasięgiem"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nie można połączyć automatycznie"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Brak dostępu do internetu"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Brak dostępu do internetu"</string>
<string name="saved_network" msgid="4352716707126620811">"Zapisane przez: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatycznie połączono przez: %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatycznie połączono przez dostawcę ocen jakości sieci"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Połączono przez %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Dostępne przez %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Połączono, brak internetu"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Połączono, brak internetu"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Punkt dostępu jest tymczasowo zajęty"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Połączono przez: %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Dostępna przez: %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Połączono z PDU"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Brak połączenia z serwerem transferu plików"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Podłączono do urządzenia wejściowego"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Połączone w celu dostępu do internetu"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Udostępnianie połączenia internetowego"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Użyj na potrzeby dostępu do internetu"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Połączono dla dostępu do internetu"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Udostępnianie połączenia z internetem"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Użyj na potrzeby dostępu do internetu"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Używaj dla mapy"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Używaj, by uzyskać dostęp do karty SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Użyj dla funkcji audio multimediów"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nie można sparować z urządzeniem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ze względu na błędny kod PIN lub klucz."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Nie można skomunikować się z urządzeniem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Powiązanie odrzucone przez urządzenie <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Komputer"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Zestaw słuchawkowy"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Obrazowanie"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Słuchawki"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Peryferyjne urządzenie wejściowe"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi wyłączone."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi odłączone."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi: jeden pasek."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Kodek dźwięku Bluetooth LDAC: jakość odtwarzania"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Wybierz kodek dźwięku Bluetooth LDAC:\njakość odtwarzania"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Strumieniowe przesyłanie danych: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS przez TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Po włączeniu wypróbuj komunikację DNS przez TLS przez port 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Prywatny DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Wybierz tryb prywatnego DNS"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Wyłączony"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunistyczny"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Nazwa hosta dostawcy prywatnego DNS"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Wpisz nazwę hosta dostawcy DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaż opcje certyfikacji wyświetlacza bezprzewodowego"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Zwiększ poziom rejestrowania Wi‑Fi, pokazuj według RSSI SSID w selektorze Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Po włączeniu połączenie danych będzie bardziej agresywnie przełączać się z Wi-Fi na sieć komórkową przy słabym sygnale Wi-Fi"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Włącz 4x MSAA w aplikacjach OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Debuguj operacje przycinania nieprostokątnego"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Profil renderowania GPU"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Warstwy debugowania GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Zezwól na ładowanie warstw debugowania GPU"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Skala animacji okna"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Skala animacji przejścia"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Skala długości animacji"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 6b2a5ca..240f850 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Verifique a senha e tente novamente"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Fora do alcance"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Não se conectará automaticamente"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Sem acesso à Internet"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Sem acesso à Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Salva por <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Conectado automaticamente via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Conectado automaticamente via provedor de avaliação de rede"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado via %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Disponível via %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Conectada, sem Internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Conectada, sem Internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Ponto de acesso temporariamente cheio"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Conectado via %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Disponível via %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Conectado a SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Não está conectado ao servidor de transferência de arquivo"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Conectado ao dispositivo de entrada"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Conectado ao dispositivo para acesso à Internet"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Compart. conexão local de Intern. com disp."</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Usar para acesso à Internet"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Conectado ao dispositivo para acesso à Internet"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Compartilhamento de conexão local de Internet c/ disposit."</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Usar para acesso à Internet"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Usar para mapa"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Use para acesso SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Usar para áudio de mídia"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g> por causa de um PIN ou senha incorretos."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Não é possível se comunicar com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Pareamento rejeitado por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Computador"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Fone de ouvido"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefone"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Imagem"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Headphone"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Periférico de entrada"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi desligado."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi desconectado"</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Uma barra de Wi-Fi."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codec de áudio Bluetooth LDAC: qualidade de reprodução"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Selecionar codec de áudio Bluetooth LDAC:\nqualidade de reprodução"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS por TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Se essa opção estiver ativada, tente o DNS por TLS na porta 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS particular"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Selecione o modo DNS particular"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Desativado"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunista"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Nome do host do provedor de DNS particular"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Informe o nome do host do provedor de DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções de certificação de Display sem fio"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de registro do Wi-Fi; mostrar conforme o RSSI de SSID na Seleção de Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Quando ativada, o Wi-Fi será mais agressivo em passar a conexão de dados para móvel, quando o sinal de Wi-Fi estiver fraco"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Ativar 4x MSAA em apps OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Depurar operações de corte não retangulares"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Classific. render. GPU"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Ativar camadas depuração de GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Permitir carreg. camadas de depuração GPU p/ apps de dep."</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Escala de anim. da janela"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Escala anim. de transição"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Escala de duração do Animator"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 1a6f0c6..4852406af 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Verifique a palavra-passe e tente novamente"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Fora do alcance"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Não é efetuada uma ligação automaticamente"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Sem acesso à Internet"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Sem acesso à Internet."</string>
<string name="saved_network" msgid="4352716707126620811">"Guardada por <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Ligado automaticamente através de %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Ligado automaticamente através do fornecedor de classificação de rede"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Ligado através de %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Disponível através de %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Ligado, sem Internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Ligado, sem Internet."</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Ponto de acesso temporariamente cheio"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Ligado através de %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Disponível através de %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Ligado ao SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Não ligado ao servidor de transferência de ficheiros"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Ligado a um dispositivo de entrada"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Ligado ao aparelho para acesso à internet"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"A partilhar a ligação à internet local com o aparelho"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Utilizar para acesso à internet"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Lig. ao disposit. p/ acesso à Internet"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"A partilhar lig. à Internet local c/ dispos."</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Utilizar para acesso à Internet"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Utilizar para o mapa"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Utilizar para acesso ao SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Utilizar para áudio de multimédia"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Não foi possível sincronizar com <xliff:g id="DEVICE_NAME">%1$s</xliff:g> devido a PIN ou chave de acesso incorreto."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Não é possível comunicar com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Emparelhamento rejeitado por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Computador"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Auscultadores com microfone integrado"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telemóvel"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Dispositivo de imagem"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Auricular"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Periférico de entrada"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi desativado."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi desligado."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Uma barra de Wi-Fi."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codec LDAC de áudio Bluetooth: qualidade de reprodução"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Selecionar codec LDAC de áudio Bluetooth:\nQualidade de reprodução"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Transmissão em fluxo contínuo: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS através de TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Se a opção estiver ativada, tente efetuar DNS através de TLS na porta 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS privado"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Selecionar modo DNS privado"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Desativado"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunista"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Nome de anfitrião do fornecedor DNS privado"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Introduza o nome de anfitrião do fornecedor DNS."</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções da certificação de display sem fios"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de reg. de Wi-Fi, mostrar por RSSI de SSID no Selec. de Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Se estiver ativado, o Wi-Fi será mais agressivo ao transmitir a lig. de dados para a rede móvel quando o sinal Wi-Fi estiver fraco"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Ativar o 4x MSAA em aplicações OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Depurar operações de clipe não retangulares"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Conversão GPU do perfil"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Ativar cam. depuração GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Permitir carreg. cam. depuração GPU p/ dep. aplic."</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Escala de anim. da janela"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Escala de anim. de trans."</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Esc. de duração do anim."</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 6b2a5ca..240f850 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Verifique a senha e tente novamente"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Fora do alcance"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Não se conectará automaticamente"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Sem acesso à Internet"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Sem acesso à Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Salva por <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Conectado automaticamente via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Conectado automaticamente via provedor de avaliação de rede"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado via %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Disponível via %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Conectada, sem Internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Conectada, sem Internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Ponto de acesso temporariamente cheio"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Conectado via %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Disponível via %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Conectado a SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Não está conectado ao servidor de transferência de arquivo"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Conectado ao dispositivo de entrada"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Conectado ao dispositivo para acesso à Internet"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Compart. conexão local de Intern. com disp."</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Usar para acesso à Internet"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Conectado ao dispositivo para acesso à Internet"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Compartilhamento de conexão local de Internet c/ disposit."</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Usar para acesso à Internet"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Usar para mapa"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Use para acesso SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Usar para áudio de mídia"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g> por causa de um PIN ou senha incorretos."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Não é possível se comunicar com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Pareamento rejeitado por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Computador"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Fone de ouvido"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefone"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Imagem"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Headphone"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Periférico de entrada"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi desligado."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi desconectado"</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Uma barra de Wi-Fi."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codec de áudio Bluetooth LDAC: qualidade de reprodução"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Selecionar codec de áudio Bluetooth LDAC:\nqualidade de reprodução"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS por TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Se essa opção estiver ativada, tente o DNS por TLS na porta 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS particular"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Selecione o modo DNS particular"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Desativado"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunista"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Nome do host do provedor de DNS particular"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Informe o nome do host do provedor de DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções de certificação de Display sem fio"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de registro do Wi-Fi; mostrar conforme o RSSI de SSID na Seleção de Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Quando ativada, o Wi-Fi será mais agressivo em passar a conexão de dados para móvel, quando o sinal de Wi-Fi estiver fraco"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Ativar 4x MSAA em apps OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Depurar operações de corte não retangulares"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Classific. render. GPU"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Ativar camadas depuração de GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Permitir carreg. camadas de depuração GPU p/ apps de dep."</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Escala de anim. da janela"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Escala anim. de transição"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Escala de duração do Animator"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 89a18ef..73869d50 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Verificați parola și încercați din nou"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"În afara ariei de acoperire"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nu se va conecta automat"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Nu există acces la internet"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Nu există acces la internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Salvată de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Conectată automat prin %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Conectată automat prin furnizor de evaluări ale rețelei"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Conectată prin %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Disponibilă prin %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Conectată, fără internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Conectată, fără internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Punctul de acces este temporar plin"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Conectată prin %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Disponibilă prin %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Conectat la SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Neconectat la serverul de transfer de fișiere"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Conectat la dispozitivul de intrare"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Conectat la dispoz. pt. acces internet"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Se permite dispoz. acces la internet local"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Utilizați pentru acces internet"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Conectat la dispoz. pt. acces internet"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Acces la internet local"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Utilizați pentru acces la internet"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Utilizați pentru hartă"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Folosiți pentru acces la SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Utilizați pentru profilul pentru conținut media audio"</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Activați MSAA 4x în aplicațiile OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Remediați decupări nerectangulare"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Profil redare cu GPU"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Activați nivelurile de depanare GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Permiteți încărcarea nivelurilor de depanare GPU pentru aplicațiile de depanare"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Scară animație fereastră"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Scară tranziție animații"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Scară durată Animator"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index d88adea..0ebf020 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Возможно, вы указали неверный пароль. Повторите попытку."</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Недоступна"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Подключение не будет выполняться автоматически"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Отсутствует подключение к Интернету"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Без доступа к Интернету"</string>
<string name="saved_network" msgid="4352716707126620811">"Кто сохранил: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Автоматически подключено к %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Автоматически подключено через автора рейтинга сетей"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Подключено к %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Доступно через %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Подключено, без Интернета"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Подключено, без доступа к Интернету"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"К точке доступа подключено слишком много устройств"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Подключено к %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Доступно через %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Подключено к точке доступа"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Нет подключения к серверу передачи файлов"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Подключено к устройству ввода"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Используется интернет-подключение другого устройства"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Устройство работает в режиме модема"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Использовать для доступа к Интернету"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Используется подключение другого устройства"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Устройство работает в режиме модема"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Использовать для доступа к Интернету"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Использовать для доступа к сообщениям"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Использовать для доступа к SIM-карте"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Использовать для мультимедийного аудиоустройства"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Не удалось установить сопряжение с устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\", так как введен неверный PIN-код или пароль."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Не удается установить соединение с устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> не разрешает сопряжение."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Компьютер"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Гарнитура"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Телефон"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Камера"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Наушники"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Периферийное устройство ввода"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi выключен"</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi отключен"</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi: одно деление"</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Аудиокодек LDAC для Bluetooth: качество воспроизведения"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Аудиокодек LDAC для Bluetooth:\nкачество воспроизведения"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Потоковая передача: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS по TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Если функция включена, соединение с DNS будет выполняться по TLS через порт 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Персональный DNS-сервер"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Выберите режим персонального DNS-сервера"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"ВЫКЛ"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Гибкий"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Имя хоста поставщика персонального DNS-сервера"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Введите имя хоста поставщика услуг DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показывать параметры сертификации беспроводных мониторов"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"При выборе Wi‑Fi указывать в журнале RSSI для каждого SSID"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Принудительно переключаться на мобильную сеть, если сигнал Wi-Fi слабый"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Включить 4x MSAA в приложениях OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Отладка операций усечения сложной формы"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Профилировать GPU-отрисовку"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Отладка графического процессора"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Включить загрузку слоев отладки графического процессора"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Анимация окон"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Анимация переходов"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Длительность анимации"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index db01eea..35631c9 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"මුරපදය පරික්ෂා කර නැවත උත්සාහ කරන්න"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"පරාසයේ නැත"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"ස්වයංක්රිය නැවත සම්බන්ධ නොවනු ඇත"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"අන්තර්ජාල ප්රවේශය නැත"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"අන්තර්ජාල ප්රවේශය නැත"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> විසින් සුරකින ලදී"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s හරහා ස්වයංක්රියව සම්බන්ධ විය"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ජාල ශ්රේණිගත සපයන්නා හරහා ස්වයංක්රියව සම්බන්ධ විය"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s හරහා සම්බන්ධ විය"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s හරහා ලබා ගැනීමට හැකිය"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"සම්බන්ධයි, අන්තර්ජාලය නැත"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"සම්බන්ධයි, අන්තර්ජාලය නැත"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ප්රවේශ ලක්ෂ්ය තාවකාලිකව පිරී ඇත"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s හරහා සම්බන්ධ විය"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s හරහා ලබා ගැනීමට හැකිය"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP වෙත සම්බන්ධ විය"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ගොනු හුවමාරු සේවාදායකය වෙත සම්බන්ධ වී නොමැත"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ආදාන උපාංග වෙත සම්බන්ධිතයි"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"අන්තර්ජාල ප්රවේශය සඳහා උපාංගය වෙත සම්බන්ධ වුණි"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"මෙම උපාංගය සමඟ පෙදෙසි අන්තර්ජාල සම්බන්ධතාවය බෙදාගනිමින්"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"අන්තර්ජාල ප්රවේශය සඳහා භාවිතා කරන්න"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"අන්තර්ජාල ප්රවේශය සඳහා උපාංගය වෙත සම්බන්ධ කරන ලදී"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"උපාංගය සමඟ පෙදෙසි අන්තර්ජාල සබැඳුම බෙදා ගනිමින්"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"අන්තර්ජාල ප්රවේශය සඳහා භාවිත කරන්න"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"සිතියම සඳහා භාවිතා කරන්න"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM ප්රවේශය සඳහා භාවිත කරන්න"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"මාධ්ය ශ්රව්ය සඳහා භාවිතා කරන්න"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"වැරදි PIN එකක් හෝ පාස් යතුරක් නිසා <xliff:g id="DEVICE_NAME">%1$s</xliff:g> සමඟ යුගල කිරීමට නොහැකිය."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> සමඟ සන්නිවේදනය කළ නොහැක."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> විසින් යුගල කිරීම ප්රතික්ෂේප කරන ලදි."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"පරිගණකය"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"හෙඩ්සෙට්"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"දුරකථනය"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"නිරූපණය"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"හෙඩ්ෆෝන්"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"ආදාන උපාංග"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"බ්ලූටූත්"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi අක්රියයි."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi සම්බන්ධ කර නොමැත."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wifi තීරු එකයි."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"බ්ලූටූත් ශ්රව්ය LDAC පසුධාවන ගුණත්වය"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"බ්ලූටූත් ශ්රව්ය LDAC කොඩෙක් තෝරන්න:\nපසුධාවන ගුණත්වය"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"ප්රවාහ කරමින්: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"TLS හරහා DNS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"සබල නම්, 853 තොට මත TLS හරහා DNS උත්සාහ කරන්න."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"පුද්ගලික DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"පුද්ගලික DNS ප්රකාරය තෝරන්න"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"ක්රියාවිරහිතයි"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"අවස්ථාවාදී"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"පුද්ගලික DNS සැපයුම්කරු සත්කාරක නම"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS සැපයුම්කරුගේ සත්කාරක නම ඇතුළු කරන්න"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"නොරැහැන් සංදර්ශක සහතිකය සඳහා විකල්ප පෙන්වන්න"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi ලොග් මට්ටම වැඩි කරන්න, Wi‑Fi තෝරනයෙහි SSID RSSI අනුව පෙන්වන්න"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"සබල විට Wi‑Fi සිග්නලය අඩු විට Wi‑Fi දත්ත සම්බන්ධතාවය ජංගම වෙත භාර දීමට වඩා ආක්රමණික වේ"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 යෙදුම්හි 4x MSAA සබල කරන්න"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"සෘජුකෝණාස්ර-නොවන ක්ලිප් මෙහෙයුම් නිදොස් කරන්න"</string>
<string name="track_frame_time" msgid="6146354853663863443">"GPU විදැහුම විස්තර කරන්න"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU නිදොසීමේ ස්තර සබල කර."</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"නිදොසීමේ යෙදුම්වලට GPU නිදොසීමේ ස්තර පූරණයට ඉඩ දෙ."</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"කවුළු සජීවිකරණ පරිමාණය"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"සංක්රමණ සජීවන පරිමාණය"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"සජීවක කාල පරාස පරිමාණය"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index fc7e1c3..c90e221 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Skontrolujte heslo a skúste to znova"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Mimo dosah"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nedôjde k automatickému pripojeniu"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Žiadny prístup k internetu"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Žiadny prístup k internetu"</string>
<string name="saved_network" msgid="4352716707126620811">"Uložila aplikácia <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Automaticky pripojené prostredníctvom %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automaticky pripojené prostredníctvom poskytovateľa hodnotenia siete"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Pripojené prostredníctvom %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"K dispozícii prostredníctvom %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Pripojené, žiadny internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Pripojené, žiadny internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Prístupový bod je dočasne plný"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Pripojené prostredníctvom operátora %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"K dispozícii prostredníctvom operátora %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Pripojené k systému SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nepripojené k serveru pre prenos súborov"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Pripojené na vstupné zariadenie"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Pripoj. k zariad. s príst. na Internet"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Zdieľa miestne internet. pripoj. so zariad"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Použiť na prístup k Internetu"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Pripojené k zariadeniu s prístupom k internetu"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Zdieľa miestne internetové pripojenie so zariadením"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Použiť na prístup k internetu"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Použiť pre mapu"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Použiť na pristupovanie k SIM karte"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Umožňuje pripojenie zvukového média"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nepodarilo sa spárovať so zariadením <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, pretože ste zadali nesprávny kód PIN alebo prístupový kľúč."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"So zariadením <xliff:g id="DEVICE_NAME">%1$s</xliff:g> nie je možné komunikovať."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Párovanie odmietnuté zariadením <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Počítač"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Náhlavná súprava"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefón"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Snímkovacie zariadenie"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Slúchadlá"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Periférne vstupné zariadenie"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Sieť Wi‑Fi je vypnutá."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Sieť Wi‑Fi je odpojená."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Jedna čiarka signálu Wi‑Fi."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Kodek LDAC Bluetooth Audio: Kvalita prehrávania"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Vybrať kodek LDAC Bluetooth Audio:\nKvalita prehrávania"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streamovanie: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS cez TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Ak túto možnosť aktivujete, zariadenie sa bude pripájať k serverom DNS pomocou protokolu TLS na porte 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Súkromné DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Výber súkromného režimu DNS"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Vypnuté"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Príležitostné"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Súkromný názov hostiteľa poskytovateľa DNS"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Zadajte názov hostiteľa poskytovateľa DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Zobraziť možnosti certifikácie bezdrôtového zobrazenia"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Zvýšiť úroveň denníkov Wi‑Fi, zobrazovať podľa SSID RSSI pri výbere siete Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Keď túto možnosť zapnete, Wi‑Fi bude agresívnejšie odovzdávať dátové pripojenie na mobilnú sieť vtedy, keď bude slabý signál Wi‑Fi"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Povoliť 4x MSAA v aplikáciách OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Ladenie operácií s neobdĺžnikovými výstrižkami"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Profil vykresľovania GPU"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Povoliť vrstvy ladenia GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Povoliť načítanie vrstiev ladenia grafického procesora na ladenie aplikácií"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Mierka animácie okna"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Mierka animácie premeny"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Mierka dĺžky animácie"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 07475d3..a131632 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Preverite geslo in poskusite znova"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Ni v obsegu"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Samodejna vnovična vzpostavitev povezave se ne bo izvedla"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Ni dostopa do interneta"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Ni dostopa do interneta"</string>
<string name="saved_network" msgid="4352716707126620811">"Shranil(-a): <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Samodejno vzpostavljena povezava prek: %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Samodejno vzpostavljena povezava prek ponudnika ocenjevanja omrežij"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Vzpostavljena povezava prek: %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Na voljo prek: %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Vzpostavljena povezava, brez interneta"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Vzpostavljena povezava, brez interneta"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Dostopna točka je trenutno zasedena"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Vzpostavljena povezava prek: %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Na voljo prek: %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Vzpostavljena povezava s profilom SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Povezava s strežnikom za prenos datotek ni vzpostavljena"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Povezava z vnosno napravo je vzpostavljena"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Povezava z napravo za internetni dostop"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Skupna raba lok. internetne povezave z napravo"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Uporabi za dostop do interneta"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Povezava z napravo za internetni dostop"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Skupna raba lok. internetne povezave z napravo"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Uporabi za dostop do interneta"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Uporabi za zemljevid"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Uporablja se za dostop do kartice SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Uporabi za zvok predstavnosti"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Zaradi nepravilne kode PIN ali gesla ni mogoče vzpostaviti povezave z napravo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Z napravo <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ni mogoče vzpostaviti povezave."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Naprava <xliff:g id="DEVICE_NAME">%1$s</xliff:g> je zavrnila seznanitev."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Računalnik"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Slušalke z mikrofonom"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Naprava za zajem slik"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Slušalka"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Zunanja dodatna oprema"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi je izklopljen."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Povezava Wi-Fi je prekinjena."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Ena črtica signala Wi-Fi."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Zvočni kodek LDAC za Bluetooth: kakovost predvajanja"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Izberi zvočni kodek LDAC za Bluetooth:\nKakovost predvajanja"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Pretočno predvajanje: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS s šifriranjem TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Če je ta možnost omogočena, poskusi vzpostaviti povezavo DNS s šifriranjem TLS na vratih 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Zasebni strežnik DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Izbira načina zasebnega strežnika DNS"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Izklopljeno"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Priložnostno"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Ime gostitelja pri ponudniku zasebnega strežnika DNS"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Vnesite ime gostitelja pri ponudniku strežnika DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaži možnosti za potrdilo brezžičnega zaslona"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povečaj raven zapis. dnev. za Wi-Fi; v izbir. Wi‑Fi-ja pokaži glede na SSID RSSI"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Če je ta možnost omogočena, Wi-Fi odločneje preda podatkovno povezavo mobilnemu omrežju, ko je signal Wi-Fi šibek."</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"V aplikacijah OpenGL ES 2.0 omogoči 4x MSAA"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Odpr. težav s postopki nepravokotnega izrezovanja"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Upod. profilov z GPE"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Omog. sloje odpr. nap. GPE"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Apl. za odpr. nap. dovoli nal. sloj. odpr. nap. GPE"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Merilo animacije okna"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Merilo animacije prehoda"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Lestvica trajanja animacije"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 4fcfc5c..d5e92dc 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Kontrollo fjalëkalimin dhe provo sërish"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Nuk është brenda rrezes"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nuk do të lidhet automatikisht"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Nuk ka qsaje në internet"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Nuk ka qasje në internet"</string>
<string name="saved_network" msgid="4352716707126620811">"E ruajtur nga <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Lidhur automatikisht përmes %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Lidhur automatikisht nëpërmjet ofruesit të vlerësimit të rrjetit"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"E lidhur përmes %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"E mundshme përmes %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"U lidh, nuk ka internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"U lidh, por nuk ka internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Pika e qasjes është përkohësisht plot"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"E lidhur përmes %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"E disponueshme përmes %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Lidhur me SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nuk u lidh me serverin e transferimit të skedarëve"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"U lidh me pajisjen e hyrjes"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Lidhur me pajisjen për qasje në internet"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Po ndan lidhjen lokale të internetit me pajisjen"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Përdor për qasje në internet"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Lidhur me pajisjen për qasje në internet"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Po ndan lidhjen lokale të internetit me pajisjen"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Përdor për qasje në internet"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Përdore për hartën"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Përdor për qasje në kartën SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Përdor për audion e medias"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nuk mundi të çiftohej me <xliff:g id="DEVICE_NAME">%1$s</xliff:g> për shkak të një kodi PIN ose një kodi të pasaktë."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Nuk mund të komunikohet me <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Çiftimi u refuzua nga <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Kompjuteri"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Kufjet me mikrofon"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Imazhe"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Kufje"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Hyrje periferike"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth-i"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi është çaktivizuar."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi është i shkëputur."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi ka një vijë."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Kodeku LDAC i audios së Bluetooth-it: Cilësia e luajtjes"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Zgjidh kodekun LDAC të audios së Bluetooth-it:\nCilësia e luajtjes"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Transmetimi: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS nëpërmjet protokollit TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Nëse është aktivizuar, provo DNS-në nëpërmjet protokollit TLS në portën 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS-ja private"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Zgjidh modalitetin e DNS-së private"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Joaktiv"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunist"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Emri i pritësit të ofruesit të DNS-së private"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Fut emrin e pritësit të ofruesit të DNS-së"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Shfaq opsionet për certifikimin e ekranit valor"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Rrit nivelin regjistrues të Wi‑Fi duke shfaqur SSID RSSI-në te Zgjedhësi i Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Kur ky funksion aktivizohet, Wi‑Fi bëhet më agresiv në kalimin e lidhjes së të dhënave te rrjeti celular, në rastet kur sinjali Wi‑Fi është i dobët"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Aktivizo 4x MSAA në aplikacionet OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Korrigjo veprimet mbi klipet jodrejtkëndore"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Interpretimi i profilit të GPU-së"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Aktivizo shtresat e korrigjimit të GPU-së"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Lejo ngarkimin e shtresave të korrigjimit të GPU-së për aplikacionet e korrigjimit"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Animacioni i dritares"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Animacioni kalimtar"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Kohëzgjatja e animatorit"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index e591aa1..94a1738 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Проверите лозинку и пробајте поново"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Није у опсегу"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Аутоматско повезивање није успело"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Нема приступа интернету"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Нема приступа интернету"</string>
<string name="saved_network" msgid="4352716707126620811">"Сачувао/ла је <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Аутоматски повезано преко %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Аутоматски повезано преко добављача оцене мреже"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Веза је успостављена преко приступне тачке %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Доступна је преко приступне тачке %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Веза је успостављена, нема интернета"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Веза је успостављена, нема интернета"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Приступна тачка је привремено заузета"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Повезано преко %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Доступно преко %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Веза са тачком приступа услугама је успостављена"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Није повезано са сервером за пренос датотека"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Повезан са улазним уређајем"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Повез. са уређ. ради приступа Интернету"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Локална интернет веза се дели са уређајем"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Користи за приступ Интернету"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Повезано је са уређајем ради приступа интернету"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Локална интернет веза се дели са уређајем"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Користи за приступ интернету"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Користи се за мапу"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Користи за приступ SIM картици"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Коришћење за звук медија"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Упаривање са уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g> није могуће због нетачног PIN-а или приступног кода."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Није могуће комуницирати са уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> је одбио/ла упаривање"</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Рачунар"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Наглавне слушалице"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Позови"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Обрада слика"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Слушалице"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Периферни уређај за унос"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi је искључен."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi веза је прекинута."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi сигнал има једну црту."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth аудио кодек LDAC: квалитет репродукције"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Изаберите Bluetooth аудио кодек LDAC:\nквалитет репродукције"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Стримовање: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS преко TLS-а"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Ако је омогућено, пробајte DNS преко TLS-а на порту 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Приватни DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Изаберите режим приватног DNS-а"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Искључено"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Оппортунистички"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Име хоста добављача услуге приватног DNS-а"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Унесите име хоста добављача услуге DNS-а"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Приказ опција за сертификацију бежичног екрана"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Повећава ниво евидентирања за Wi‑Fi. Приказ по SSID RSSI-у у бирачу Wi‑Fi мреже"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Кад се омогући, Wi‑Fi ће бити агресивнији при пребацивању мреже за пренос података на мобилну ако је Wi‑Fi сигнал слаб"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Омогући 4x MSAA у OpenGL ES 2.0 апликацијама"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Отклони грешке у вези са радњама за исецање области које нису правоугаоног облика"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Прикажи профил помоћу GPU"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Омогући слојеве за отклањање грешака GPU-a"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Омогући учитавање слоj. за отк. греш. GPU-a у апл. за отк. греш."</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Размера анимације прозора"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Размера анимације прелаза"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Аниматорова размера трајања"</string>
diff --git a/packages/SettingsLib/res/values-sv/arrays.xml b/packages/SettingsLib/res/values-sv/arrays.xml
index cc7bcc8..de1e54f 100644
--- a/packages/SettingsLib/res/values-sv/arrays.xml
+++ b/packages/SettingsLib/res/values-sv/arrays.xml
@@ -231,7 +231,7 @@
</string-array>
<string-array name="debug_hw_overdraw_entries">
<item msgid="8190572633763871652">"Av"</item>
- <item msgid="7688197031296835369">"Visa områden som överskrider gränsen"</item>
+ <item msgid="7688197031296835369">"Visa överritningsområden"</item>
<item msgid="2290859360633824369">"Visa områden för deuteranomali"</item>
</string-array>
<string-array name="debug_hw_renderer_entries">
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index cb86b5b..5a7dca3 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Kontrollera lösenordet och försök igen"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Utom räckhåll"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Det går inte att ansluta automatiskt"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Ingen internetåtkomst"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Ingen internetåtkomst"</string>
<string name="saved_network" msgid="4352716707126620811">"Sparades av <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatiskt ansluten via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatiskt ansluten via leverantör av nätverksbetyg"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Anslutet via %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Tillgängligt via %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Ansluten, inget internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Ansluten, inget internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Åtkomstpunkten har inga platser över för tillfället"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Anslutet via %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Tillgängligt via %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Ansluten till SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Inte ansluten till filöverföringsserver"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Ansluten till indataenhet"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Ansluten för Internetåtkomst"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Dela lokal Internetanslutning med enhet"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Använd för Internetåtkomst"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Ansluten för internetåtkomst"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Dela lokal internetanslutning med enhet"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Använd för internetåtkomst"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Använd för MAP"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Använd för SIM-åtkomst"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Använd för medialjud"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Det gick inte att koppla till <xliff:g id="DEVICE_NAME">%1$s</xliff:g> på grund av en felaktig PIN-kod eller nyckel."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Det går inte att kommunicera med <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Parkoppling avvisad av <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Dator"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Headset"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Mobil"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Bild"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Hörlur"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Inmatning från kringutrustning"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi är inaktiverat."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Ingen Wi-Fi-anslutning."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi: en stapel."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth-ljud via LDAC-kodek: uppspelningskvalitet"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Välj Bluetooth-ljud via LDAC-kodek:\nuppspelningskvalitet"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS via TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Om inställningen är aktiverad görs försök att använda DNS via TLS på port 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privat DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Välj läget Privat DNS"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Av"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistisk"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Värdnamn för leverantör av privat DNS"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Ange värdnamn för DNS-leverantör"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Visa certifieringsalternativ för Wi-Fi-skärmdelning"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Öka loggningsnivån för Wi-Fi, visa per SSID RSSI i Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"När funktionen har aktiverats kommer dataanslutningen lämnas över från Wi-Fi till mobilen på ett aggressivare sätt när Wi-Fi-signalen är svag"</string>
@@ -267,7 +278,7 @@
<string name="show_hw_screen_updates_summary" msgid="1115593565980196197">"Visningar blinkar i fönster vid GPU-ritningar"</string>
<string name="show_hw_layers_updates" msgid="5645728765605699821">"Visa maskinvaruskiktuppd."</string>
<string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Låt maskinvaruskikt blinka grönt vid uppdateringar"</string>
- <string name="debug_hw_overdraw" msgid="2968692419951565417">"Felsök överskriden GPU"</string>
+ <string name="debug_hw_overdraw" msgid="2968692419951565417">"Felsök GPU-överritning"</string>
<string name="debug_hw_renderer" msgid="7568529019431785816">"Ange GPU-renderare"</string>
<string name="disable_overlays" msgid="2074488440505934665">"Inaktivera HW-överlagringar"</string>
<string name="disable_overlays_summary" msgid="3578941133710758592">"Använd alltid GPU för skärmsammansättning"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Aktivera 4x MSAA i OpenGL ES 2.0-appar"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Felsök icke-rektangulära urklippsåtgärder"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Profilens GPU-rendering"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Aktivera GPU-felsökningslager"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Tillåt att felsökningsappar läser in GPU-felsökningslager"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Skala, fönsteranimering"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Skala, övergångsanimering"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Längdskala för Animator"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index b84194d..01db36a 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -33,15 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Angalia nenosiri na ujaribu tena"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Haiko karibu"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Haiwezi kuunganisha kiotomatiki"</string>
- <!-- no translation found for wifi_no_internet (4663834955626848401) -->
- <skip />
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Hakuna muunganisho wa intaneti"</string>
<string name="saved_network" msgid="4352716707126620811">"Ilihifadhiwa na <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Imeunganishwa kiotomatiki kupitia %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Imeunganishwa kiotomatiki kupitia mtoa huduma wa ukadiriaji wa mtandao"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Imeunganishwa kupitia %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Inapatikana kupitia %1$s"</string>
- <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Imeunganishwa, hakuna intaneti"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Lango la mtandao lina shughuli nyingi kwa sasa"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Imeunganishwa kupitia %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Inapatikana kupitia %1$s"</string>
@@ -86,8 +84,7 @@
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Umeunganishwa kwa kifaa cha kuingiza"</string>
<string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Imeunganishwa kwenye kifaa ili kufikia intaneti"</string>
<string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Inashiriki muunganisho wa intaneti wa kifaa na kifaa kingine"</string>
- <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
- <skip />
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Tumia kuunganisha kwenye intaneti"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Tumia kwa ramani"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Tumia kwa ufikiaji wa SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Tumia kwa sauti ya media"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index cb57c71..71dcd0f 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -33,15 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"கடவுச்சொல்லைச் சரிபார்த்து, மீண்டும் முயலவும்"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"தொடர்பு எல்லையில் இல்லை"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"தானாக இணைக்கப்படாது"</string>
- <!-- no translation found for wifi_no_internet (4663834955626848401) -->
- <skip />
+ <string name="wifi_no_internet" msgid="4663834955626848401">"இண்டர்நெட் அணுகல் இல்லை"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> சேமித்தது"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s மூலம் தானாக இணைக்கப்பட்டது"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"நெட்வொர்க் மதிப்பீடு வழங்குநரால் தானாக இணைக்கப்பட்டது"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s வழியாக இணைக்கப்பட்டது"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s வழியாகக் கிடைக்கிறது"</string>
- <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"இணைக்கப்பட்டுள்ளது, ஆனால் இண்டர்நெட் இல்லை"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"தற்காலிகமாக அணுகல் புள்ளி நிரம்பியுள்ளது"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s வழியாக இணைக்கப்பட்டது"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s வழியாகக் கிடைக்கிறது"</string>
@@ -86,8 +84,7 @@
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"உள்ளீட்டுச் சாதனத்துடன் இணைக்கப்பட்டது"</string>
<string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"சாதனத்துடன் இணைந்தது"</string>
<string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"சாதனத்துடன் உள்ளூர் இண்டர்நெட்டைப் பகிர்தல்"</string>
- <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
- <skip />
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"இண்டர்நெட்டை அணுகப் பயன்படுத்து"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"வரைபடத்திற்குப் பயன்படுத்து"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"சிம் அணுகலுக்குப் பயன்படுத்தும்"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"மீடியாவின் ஆடியோவிற்குப் பயன்படுத்து"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index b6f1bd2..7db8e0d 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"పాస్వర్డ్ను తనిఖీ చేసి, మళ్లీ ప్రయత్నించండి"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"పరిధిలో లేదు"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"స్వయంచాలకంగా కనెక్ట్ కాదు"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ద్వారా సేవ్ చేయబడింది"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s ద్వారా స్వయంచాలకంగా కనెక్ట్ చేయబడింది"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"నెట్వర్క్ రేటింగ్ ప్రదాత ద్వారా స్వయంచాలకంగా కనెక్ట్ చేయబడింది"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ద్వారా కనెక్ట్ చేయబడింది"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s ద్వారా అందుబాటులో ఉంది"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"కనెక్ట్ చేయబడింది, ఇంటర్నెట్ లేదు"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"కనెక్ట్ చేయబడింది, ఇంటర్నెట్ లేదు"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"యాక్సెస్ పాయింట్ తాత్కాలికంగా నిండుకుంది"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s ద్వారా కనెక్ట్ చేయబడింది"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s ద్వారా అందుబాటులో ఉంది"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAPకి కనెక్ట్ చేయబడింది"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ఫైల్ బదిలీ సర్వర్కు కనెక్ట్ చేయబడలేదు"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ఇన్పుట్ పరికరానికి కనెక్ట్ చేయబడింది"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"ఇంటర్నెట్ యాక్సెస్ కోసం పరికరానికి కనెక్ట్ చేయబడింది"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"స్థానిక ఇంటర్నెట్ కనెక్షన్ను పరికరంతో భాగస్వామ్యం చేయడం"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ఇంటర్నెట్ యాక్సెస్ కోసం ఉపయోగించు"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"ఇంటర్నెట్ యాక్సెస్ కోసం పరికరానికి కనెక్ట్ చేయబడింది"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"స్థానిక ఇంటర్నెట్ కనెక్షన్ను పరికరంతో షేర్ చేయడం"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"ఇంటర్నెట్ యాక్సెస్ కోసం ఉపయోగించు"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"మ్యాప్ కోసం ఉపయోగించు"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM యాక్సెస్ కోసం ఉపయోగించబడుతుంది"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"మీడియా ఆడియో కోసం ఉపయోగించు"</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 అనువర్తనాల్లో 4x MSAAను ప్రారంభించండి"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"దీర్ఘ చతురస్రం కాని క్లిప్ చర్యలను డీబగ్ చేయండి"</string>
<string name="track_frame_time" msgid="6146354853663863443">"ప్రొఫైల్ GPU భాషాంతరీకరణ"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU డీబగ్ లేయర్లను ప్రారంభించండి"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"డీబగ్ యాప్ల కోసం GPU డీబగ్ లేయర్లను లోడ్ చేయడాన్ని అనుమతించండి"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"విండో యానిమేషన్ ప్రమాణం"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"పరివర్తన యానిమేషన్ ప్రమాణం"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"యానిమేటర్ వ్యవధి ప్రమాణం"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 2db6178..f2f1c90 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"ตรวจสอบรหัสผ่านและลองอีกครั้ง"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"ไม่อยู่ในพื้นที่ให้บริการ"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"จะไม่เชื่อมต่อโดยอัตโนมัติ"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"ไม่สามารถเข้าถึงอินเทอร์เน็ต"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"เข้าถึงอินเทอร์เน็ตไม่ได้"</string>
<string name="saved_network" msgid="4352716707126620811">"บันทึกโดย <xliff:g id="NAME">%1$s</xliff:g> แล้ว"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"เชื่อมต่ออัตโนมัติผ่าน %1$s แล้ว"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"เชื่อมต่ออัตโนมัติผ่านผู้ให้บริการการจัดอันดับเครือข่าย"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"เชื่อมต่อผ่าน %1$s แล้ว"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"พร้อมใช้งานผ่านทาง %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"เชื่อมต่อแล้ว ไม่พบอินเทอร์เน็ต"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"เชื่อมต่อแล้ว ไม่พบอินเทอร์เน็ต"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"จุดเข้าใช้งานเต็มชั่วคราว"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"เชื่อมต่อผ่าน %1$s แล้ว"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"พร้อมใช้งานผ่านทาง %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"เชื่อมต่อ SAP แล้ว"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ไม่ได้เชื่อมต่อกับเซิร์ฟเวอร์สำหรับโอนไฟล์"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"เชื่อมต่อกับอุปกรณ์อินพุตแล้ว"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"เชื่อมต่อกับอุปกรณ์สำหรับการเข้าถึงอินเทอร์เน็ต"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"กำลังแชร์อินเทอร์เน็ตกับอุปกรณ์"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ใช้การเข้าถึงอินเทอร์เน็ต"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"เชื่อมต่ออินเทอร์เน็ตแล้ว"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"กำลังแชร์อินเทอร์เน็ตกับอุปกรณ์"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"ใช้สำหรับการเข้าถึงอินเทอร์เน็ต"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"ใช้สำหรับแผนที่"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"ใช้สำหรับการเข้าถึงซิม"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"ใช้สำหรับระบบเสียงของสื่อ"</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"เปิดใช้งาน 4x MSAA ในแอปพลิเคชัน OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"แก้ไขการทำงานของคลิปที่ไม่ใช่สี่เหลี่ยม"</string>
<string name="track_frame_time" msgid="6146354853663863443">"การแสดงผล GPU ตามโปรไฟล์"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"เปิดใช้เลเยอร์การแก้ไขข้อบกพร่อง GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"อนุญาตให้โหลดเลเยอร์การแก้ไขข้อบกพร่อง GPU สำหรับแอปแก้ไขข้อบกพร่อง"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"ขนาดหน้าต่างภาพเคลื่อนไหว"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"อัตราการสลับภาพเคลื่อนไหว"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"ความเร็วตามผู้สร้างกำหนด"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 6021d79..871c384 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Suriin ang password at subukang muli"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Wala sa sakop"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Hindi awtomatikong kokonekta"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Walang access sa Internet"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Walang access sa internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Na-save ng <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Awtomatikong nakakonekta sa pamamagitan ng %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Awtomatikong nakakonekta sa pamamagitan ng provider ng rating ng network"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Nakakonekta sa pamamagitan ng %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Available sa pamamagitan ng %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Nakakonekta, walang Internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Nakakonekta, walang internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Pansamantalang puno ang access point"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Nakakonekta sa pamamagitan ng %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Available sa pamamagitan ng %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Nakakonekta sa SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Hindi konektado sa server ng paglipat ng file"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Nakakonekta sa device ng input"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Konektado sa device sa Internet access"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Pagbahagi lokal koneksyon sa Internet sa device"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Gamitin para sa pag-access sa Internet"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Nakakonekta sa device para sa access sa internet"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Pagbabahagi ng lokal na koneksyon sa internet sa device"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Gamitin para sa pag-access sa internet"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Gamitin para sa mapa"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Gamitin para sa pag-access sa SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Gamitin para sa media audio"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Hindi maipares sa <xliff:g id="DEVICE_NAME">%1$s</xliff:g> dahil sa maling PIN o passkey."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Hindi magawang makipag-ugnay sa <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Tinanggihan ng <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ang pagpapares."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Computer"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Headset"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telepono"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Imaging"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Headphone"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Input Peripheral"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Naka-off ang Wifi."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Nakadiskonekta ang Wifi."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"May isang bar ang Wifi."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Audio LDAC Codec ng Bluetooth: Kalidad ng Pag-playback"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Piliin ang Audio LDAC Codec ng Bluetooth:\nKalidad ng Pag-playback"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS sa pamamagitan ng TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Kung naka-enable, subukan ang DNS sa pamamagitan ng TLS sa port 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Pribadong DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Pumili ng Pribadong DNS Mode"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Naka-off"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunista"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Hostname ng provider ng pribadong DNS"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Ilagay ang hostname ng DNS provider"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Ipakita ang mga opsyon para sa certification ng wireless display"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Pataasin ang antas ng Wi‑Fi logging, ipakita sa bawat SSID RSSI sa Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Kapag na-enable, magiging mas agresibo ang Wi‑Fi sa paglipat sa koneksyon ng mobile data kapag mahina ang signal ng Wi‑Fi"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Paganahin ang 4x MSAA sa OpenGL ES 2.0 na apps"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"I-debug ang di-parihabang mga clip operation"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Pag-render ng Profile GPU"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"I-enable ang GPU debug layer"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Payagang i-load ang GPU debug layer sa debug app"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Scale ng window animation"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Scale ng transition animation"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Scale ng tagal ng animator"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 367f84b..7b98d58 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Şifreyi kontrol edin ve tekrar deneyin"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Kapsama alanı dışında"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Otomatik olarak bağlanma"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"İnternet erişimi yok"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"İnternet erişimi yok"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tarafından kaydedildi"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s üzerinden otomatik olarak bağlı"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Ağ derecelendirme sağlayıcı aracılığıyla otomatik olarak bağlandı"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s üzerinden bağlı"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s üzerinden kullanılabilir"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Bağlı, İnternet yok"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Bağlı, internet yok"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Erişim noktası geçici olarak dolu"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s üzerinden bağlı"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s üzerinden kullanılabilir"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP\'ye bağlı"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Dosya aktarım sunucusuna bağlanmadı"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Giriş cihazına bağlı"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"İnternet erişimi için cihaza bağlandı"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Cihazla yerel Intrnt bağlantısını paylaşıyor"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"İnternet erişimi için kullan"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"İnternet erişimi için cihaza bağlandı"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Cihazla yerel internet bağlantısını paylaşıyor"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"İnternet erişimi için kullan"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"MAP için kullan"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM erişimi için kullan"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Medya sesi için kullan"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"PIN veya parola yanlış olduğundan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ile eşlenemedi"</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ile iletişim kurulamıyor."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Eşleme <xliff:g id="DEVICE_NAME">%1$s</xliff:g> tarafından reddedildi."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Bilgisayar"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Mikrofonlu kulaklık"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Görüntüleme"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Kulaklık"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Giriş Çevre Birimi"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Kablosuz kapalı."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Kablosuz bağlantı kesildi."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Kablosuz sinyal gücü tek çubuk."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth Ses LDAC Codec\'i: Oynatma Kalitesi"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Bluetooth Ses LDAC Codec\'ini Seçin:\nOynatma Kalitesi"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Akış: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"TLS üzerinden DNS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Etkinleştirildiyse, 853 numaralı bağlantı noktasında TLS üzerinden DNS\'yi deneyin."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Gizli DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Gizli DNS Modunu Seçin"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Kapalı"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Fırsatçı"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Gizli DNS sağlayıcının ana makine adı"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS sağlayıcının ana makine adını gir"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Kablosuz ekran sertifikası seçeneklerini göster"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Kablosuz günlük kaydı seviyesini artır. Kablosuz Seçici\'de her bir SSID RSSI için göster."</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Etkinleştirildiğinde, kablosuz ağ sinyali zayıfken veri bağlantısının mobil ağa geçirilmesinde daha agresif olunur"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 uygulamalarda 4x MSAA\'yı etkinleştir"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Dikdörtgen olmayan kırpma işlemlerinde hata ayıkla"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Profil GPU oluşturma"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU hata ayıklama katmanlarını etkinleştir"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Hata ayıklama uygulamaları için GPU hata ayıklama katmanlarının yüklenmesine izin ver"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Pencere animasyonu ölçeği"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Geçiş animasyonu ölçeği"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Animatör süre ölçeği"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 2693002..9514b2b 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Перевірте пароль і повторіть спробу"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Не в діапазоні"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Не під’єднуватиметься автоматично"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Немає доступу до Інтернету"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Немає доступу до Інтернету"</string>
<string name="saved_network" msgid="4352716707126620811">"Збережено додатком <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Автоматично під’єднано через %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Автоматично під’єднано через постачальника оцінки якості мережі"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Під’єднано через %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Доступ через %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Під’єднано, але немає доступу до Інтернету"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Під’єднано, але немає доступу до Інтернету"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Точка доступу тимчасово переповнена"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Під’єднано через мережу %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Доступ через мережу %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Під’єднано до точки доступу"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Не підключ. до сервера передачі файлів"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Підключено до пристрою введ."</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Під’єдн. до пристр. для дост.до Інтерн."</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Доступ до локал.з’єдн. з Інтерн. ч-з пристрій"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Використовувати для доступу до Інтернету"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Під’єднано до пристрою для доступу до Інтернету"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Пристрій має доступ до локального інтернет-з’єднання"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Використовувати для доступу до Інтернету"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Використовувати для карти"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Використовувати для доступу до SIM-карти"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Викор. для аудіоджер."</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Не вдалося створити пару з пристроєм <xliff:g id="DEVICE_NAME">%1$s</xliff:g> через неправильний PIN-код чи ключ доступу."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Неможливо зв’язатися з пристроєм <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Створ. пари відхилено <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Комп’ютер"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Гарнітура"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Телефон"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Візуалізація"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Навушники"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Периферійне введення"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi вимкнено."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi від’єднано."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Одна смужка сигналу Wi-Fi."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Кодек для аудіо Bluetooth LDAC: якість відтворення"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Вибрати кодек для аудіо Bluetooth LDAC:\nякість відтворення"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Трансляція: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS через протокол TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Якщо ввімкнено, спробуйте DNS через протокол TLS у порту 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Приватна DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Виберіть режим \"Приватна DNS\""</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Вимкнено"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Періодично доступно"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Ім’я хосту приватного постачальника послуг DNS"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Введіть ім’я хосту постачальника послуг DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показати параметри сертифікації бездротового екрана"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Показувати в журналі RSSI для кожного SSID під час вибору Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Примусово перемикатися на мобільну мережу, коли сигнал Wi-Fi слабкий"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Увімкнути 4x MSAA в програмах OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Налагодити операції непрямокутної обрізки"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Запис часу роботи GPU"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Увімкнути шари налагодження ГП"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Дозвольте завантажувати шари налагодження ГП для додатків налагодження"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Анімація вікон"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Анімація переходів"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Тривалість анімації"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 3b6ab4a5..a344c65 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"پاسورڈ چیک کر کے دوبارہ کوشش کریں"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"رینج میں نہیں ہے"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"خودکار طور پر منسلک نہیں ہو گا"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"انٹرنیٹ تک کوئی رسائی نہیں"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"انٹرنیٹ تک کوئی رسائی نہیں"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> کی جانب سے محفوظ کردہ"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s کے ذریعے از خود منسلک کردہ"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"نیٹ ورک درجہ بندی کے فراہم کنندہ کے ذریعے از خود منسلک"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"منسلک بذریعہ %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"دستیاب بذریعہ %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"منسلک، انٹرنیٹ نہیں ہے"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"منسلک، انٹرنیٹ نہیں ہے"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"رسائی پوائنٹ عارضی طور پر فُل ہے"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"منسلک بذریعہ %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"دستیاب بذریعہ %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP سے منسلک"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"فائل منتقلی سرور سے مربوط نہیں ہے"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ان پٹ آلہ سے مربوط"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"انٹرنیٹ رسائی کیلئے آلہ سے مربوط ہو گیا"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"آلہ کے ساتھ مقامی انٹرنیٹ کنکشن کا اشتراک کر رہا ہے"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"انٹرنیٹ رسائی کیلئے استعمال"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"انٹرنیٹ رسائی کیلئے آلہ سے مربوط ہے"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"آلہ کے ساتھ مقامی انٹرنیٹ کنکشن کا اشتراک ہو رہا ہے"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"انٹرنیٹ رسائی کیلئے استعمال کریں"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"نقشہ کیلئے استعمال کریں"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM رسائی کے لئے استعمال کریں"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"میڈیا آڈیو کیلئے استعمال کریں"</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 ایپس میں 4x MSAA فعال کریں"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"غیر مستطیل نما کلپ آپریشنز ڈیبگ کریں"</string>
<string name="track_frame_time" msgid="6146354853663863443">"پروفائل GPU رینڈرنگ"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU ڈیبگ پرتیں فعال کریں"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"ڈیبگ ایپس کیلئے GPU ڈیبگ پرتوں کو لوڈ کرنے دیں"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"ونڈو اینیمیشن اسکیل"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"منتقلی اینیمیشن اسکیل"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"اینیمیٹر دورانیے کا اسکیل"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index e638b69..b222caf 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -33,15 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Parolni tekshirib, qaytadan urining"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Xizmat doirasidan tashqarida"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Avtomatik ravishda ulanilmaydi"</string>
- <!-- no translation found for wifi_no_internet (4663834955626848401) -->
- <skip />
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Internet aloqasi yo‘q"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tomonidan saqlangan"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s orqali avtomatik ulandi"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Tarmoqlar reytingi muallifi orqali avtomatik ulandi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s orqali ulangan"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s orqali ishlaydi"</string>
- <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Ulangan, lekin internet aloqasi yo‘q"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Internet kirish nuqtasi vaqtinchalik to‘lgan"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s orqali ulangan"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s orqali ishlaydi"</string>
@@ -86,8 +84,7 @@
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Kiritish qurilmasiga ulanildi"</string>
<string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Internet manbai qurilmasiga ulanildi"</string>
<string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Qurilma modem rejimida ishlamoqda"</string>
- <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
- <skip />
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Internetga kirish uchun foydalanish"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Xaritada foydalanish"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM-kartaga kirish uchun foydalanish"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Audio qurilma uchun foydalanish"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 8beb819..64fbd93 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Kiểm tra mật khẩu và thử lại"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Ngoài vùng phủ sóng"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Sẽ không tự động kết nối"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Không có quyền truy cập Internet"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Không có quyền truy cập Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Được lưu bởi <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Tự động được kết nối qua %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Tự động được kết nối qua nhà cung cấp dịch vụ xếp hạng mạng"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Được kết nối qua %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Có sẵn qua %1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Đã kết nối, không có Internet"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Đã kết nối, không có Internet"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Điểm truy cập tạm thời đã đạt đến giới hạn số lượng thiết bị truy cập."</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Được kết nối qua %1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Có sẵn qua %1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Được kết nối với SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Chưa kết nối với máy chủ chuyển tệp"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Đã kết nối với thiết bị nhập"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Đã kết nối với thiết bị"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Chia sẻ kết nối Internet"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Sử dụng để truy cập Internet"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Đã kết nối với thiết bị để truy cập Internet"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Chia sẻ kết nối Internet cục bộ với thiết bị"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Sử dụng để truy cập Internet"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Sử dụng cho bản đồ"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Sử dụng để truy cập SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Sử dụng cho âm thanh phương tiện"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Không thể ghép nối với <xliff:g id="DEVICE_NAME">%1$s</xliff:g> do mã PIN hoặc mã xác nhận không đúng."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Không thể kết nối với <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Ghép nối bị <xliff:g id="DEVICE_NAME">%1$s</xliff:g> từ chối."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Máy tính"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Tai nghe"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Điện thoại"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Tạo ảnh"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Tai nghe"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Thiết bị ngoại vi vào"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Đã tắt Wi-Fi."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Đã ngắt kết nối Wi-Fi."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Tín hiệu Wi-Fi một vạch."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codec LDAC âm thanh Bluetooth: Chất lượng phát lại"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Chọn Codec LDAC âm thanh Bluetooth:\nChất lượng phát lại"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Truyền trực tuyến: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS qua TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Nếu được bật, hãy thử DNS qua TLS trên cổng 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS riêng tư"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Chọn chế độ DNS riêng tư"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Tắt"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Cơ hội"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Tên máy chủ của nhà cung cấp DNS riêng tư"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Nhập tên máy chủ của nhà cung cấp DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Hiển thị tùy chọn chứng nhận hiển thị không dây"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Tăng mức ghi nhật ký Wi‑Fi, hiển thị mỗi SSID RSSI trong bộ chọn Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Khi được bật, Wi‑Fi sẽ tích cực hơn trong việc chuyển vùng kết nối dữ liệu sang mạng di động khi tín hiệu Wi‑Fi yếu"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Bật 4x MSAA trong ứng dụng OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Gỡ lỗi h.động của clip khác hình chữ nhật"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Kết xuất GPU cấu hình"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Bật lớp gỡ lỗi GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Cho phép tải lớp gỡ lỗi GPU cho ứng dụng gỡ lỗi"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Tỷ lệ hình động của cửa sổ"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Tỷ lệ hình động chuyển tiếp"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Tỷ lệ thời lượng"</string>
@@ -385,7 +398,7 @@
<string name="retail_demo_reset_message" msgid="118771671364131297">"Nhập mật khẩu để tiến hành khôi phục cài đặt gốc ở chế độ trình diễn"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Tiếp theo"</string>
<string name="retail_demo_reset_title" msgid="696589204029930100">"Yêu cầu mật khẩu"</string>
- <string name="active_input_method_subtypes" msgid="3596398805424733238">"Phương pháp nhập liệu hoạt động"</string>
+ <string name="active_input_method_subtypes" msgid="3596398805424733238">"Phương thức nhập đang hoạt động"</string>
<string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"Sử dụng ngôn ngữ hệ thống"</string>
<string name="failed_to_open_app_settings_toast" msgid="1251067459298072462">"Không thể mở cài đặt cho <xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g>"</string>
<string name="ime_security_warning" msgid="4135828934735934248">"Phương thức nhập này có thể thu thập tất cả văn bản bạn nhập, bao gồm dữ liệu cá nhân như mật khẩu và số thẻ tín dụng. Phương thức nhập này đến từ ứng dụng <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g>. Sử dụng phương thức nhập này?"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index dd58cc9..8029727 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"请检查密码,然后重试"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"不在范围内"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"无法自动连接"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"无法连接到互联网"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"无法访问互联网"</string>
<string name="saved_network" msgid="4352716707126620811">"由<xliff:g id="NAME">%1$s</xliff:g>保存"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"已通过%1$s自动连接"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"已自动连接(通过网络评分服务提供方)"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"已通过%1$s连接"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"可通过%1$s连接"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"已连接,但无法访问互联网"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"已连接,但无法访问互联网"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"接入点暂时满载"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"已通过%1$s连接"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"可通过%1$s连接"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"已连接到 SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"未连接到文件传输服务器"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"已连接到输入设备"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"经由其他设备连接到互联网"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"与其他设备共享该设备的互联网连接"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"用于连接互联网"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"经由其他设备连接到互联网"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"与其他设备共享该设备的互联网连接"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"用于访问互联网"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"用于地图"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"用于存取 SIM 卡"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"用于媒体音频"</string>
@@ -296,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"在 OpenGL ES 2.0 应用中启用 4x MSAA"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"调试非矩形剪裁操作"</string>
<string name="track_frame_time" msgid="6146354853663863443">"GPU 呈现模式分析"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"启用 GPU 调试层"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"允许为调试应用加载 GPU 调试层"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"窗口动画缩放"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"过渡动画缩放"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"动画程序时长缩放"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index c489850..dcec71f 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"請檢查密碼,然後再試一次"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"超出可用範圍"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"不會自動連線"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"無法偵測互聯網連線"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"無法連接互聯網"</string>
<string name="saved_network" msgid="4352716707126620811">"由「<xliff:g id="NAME">%1$s</xliff:g>」儲存"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"已透過 %1$s 自動連線"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"已透過網絡評分供應商自動連線"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"已透過 %1$s 連線"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"可透過 %1$s 連線"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"已連線,沒有互聯網"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"已連線,但沒有互聯網"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"存取點暫時已滿"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"已透過 %1$s 連線"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"可透過 %1$s 連線"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"已連接 SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"未連線至檔案傳輸伺服器"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"已連線至輸入裝置"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"已連線至裝置並取得互聯網連線"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"與裝置分享本地互聯網連線"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"用於上網"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"已連線至裝置並取得互聯網連線"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"與裝置分享本機互聯網連線"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"用於互聯網連線"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"用於地圖"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"用來存取 SIM 卡"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"用於媒體音效"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"無法與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 配對,因為 PIN 碼或密鑰不正確。"</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"無法與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 通訊。"</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」拒絕配對要求。"</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"電腦"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"耳機"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"電話"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"映像設備"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"耳機"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"輸入周邊設備"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"藍牙"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi 已關閉。"</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi 連線已中斷。"</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi 訊號一格。"</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"藍牙音訊 LDAC 編解碼器:播放品質"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"選擇藍牙音訊 LDAC 編解碼器:\n播放品質"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"正在串流:<xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"透過傳輸層安全性 (TLS) 執行網域名稱系統 (DNS)"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"如果啟用這個選項,即可在連接埠 853 上嘗試「透過傳輸層安全性 (TLS) 執行網域名稱系統 (DNS)」。"</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"不公開的網域名稱系統 (DNS)"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"選取不公開的網域名稱系統 (DNS) 模式"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"停用"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"隨機"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"不公開的網域名稱系統 (DNS) 供應商主機名稱"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"輸入網域名稱系統 (DNS) 供應商的主機名稱"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"顯示無線螢幕分享認證的選項"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"讓 Wi‑Fi 記錄功能升級,在 Wi‑Fi 選擇器中依每個 SSID RSSI 顯示 Wi‑Fi 詳細紀錄"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"啟用後,Wi-Fi 連線會在訊號不穩定的情況下更積極轉換成流動數據連線"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"在 OpenGL ES 2.0 應用程式中啟用 4x MSAA"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"對非矩形裁剪操作進行偵錯"</string>
<string name="track_frame_time" msgid="6146354853663863443">"分析 GPU 轉譯"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"啟用 GPU 偵錯圖層"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"允許為偵錯應用程式載入 GPU 偵錯圖層"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"視窗動畫比例"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"轉場動畫比例"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Animator 片長比例"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 13053f8..28def2d 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -33,15 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"請檢查密碼,然後再試一次"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"不在有效範圍內"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"無法自動連線"</string>
- <!-- no translation found for wifi_no_internet (4663834955626848401) -->
- <skip />
+ <string name="wifi_no_internet" msgid="4663834955626848401">"沒有可用的網際網路連線"</string>
<string name="saved_network" msgid="4352716707126620811">"由「<xliff:g id="NAME">%1$s</xliff:g>」儲存"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"已透過 %1$s 自動連線"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"已透過網路評分供應商自動連線"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"已透過 %1$s 連線"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"可透過 %1$s 使用"</string>
- <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"已連線,沒有網際網路"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"存取點暫時滿載"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"已透過 %1$s 連線"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"可透過 %1$s 使用"</string>
@@ -86,8 +84,7 @@
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"已連線到輸入裝置"</string>
<string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"已連線至裝置並取得網際網路連線"</string>
<string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"與裝置分享本地網際網路連線"</string>
- <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
- <skip />
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"用於網際網路連線"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"地圖使用偏好"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"用於 SIM 卡存取權"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"用於媒體音訊"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 928eac5..337bd57 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -33,13 +33,13 @@
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Hlola iphasiwedi uphinde uzame futhi"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Ayikho ebubanzini"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Ngeke ize ixhumeke ngokuzenzakalela"</string>
- <string name="wifi_no_internet" msgid="3880396223819116454">"Akukho ukufinyelela ku-inthanethi"</string>
+ <string name="wifi_no_internet" msgid="4663834955626848401">"Akukho ukufinyelela kwe-inthanethi"</string>
<string name="saved_network" msgid="4352716707126620811">"Kulondolozwe ngu-<xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Ixhumeke ngokuzenzakalela nge-%1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Kuxhunywe ngokuzenzakalelayo ngomhlinzeki wesilinganiso wenethiwekhi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Kuxhumeke nge-%1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Iyatholakala nge-%1$s"</string>
- <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Kuxhumekile, ayikho i-inthanethi"</string>
+ <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Kuxhunyiwe, ayikho i-inthanethi"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Iphoyinti lokufinyelela ligcwele okwesikhashana"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"Kuxhumeke nge-%1$s"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"Iyatholakala nge-%1$s"</string>
@@ -82,9 +82,9 @@
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Kuxhumeke ku-SAP"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Ayixhunyiwe kwiseva sokudlulisa ifayela"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Ixhunywe kwidivaysi yokufakwayo"</string>
- <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Ixhunyiwe kwidivaysi yokufinyelela kwi-Inthanethi"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Yabelana noxhumano lwe-Inthanethi kanye nedivaysi"</string>
- <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Sebenzisa ukufinyelela i-Inthanethi"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Ixhunyiwe kwidivayisi yokufinyelela kwi-Inthanethi"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Yabelana noxhumano lwe-Inthanethi kanye nedivaysi"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Sebenzisela ukufinyelela kwe-inthanethi"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Sebenzisela imephu"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Ukusebenzisa kokufinyelela kwe-SIM"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Sebenzisela umsindo wemidiya"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Ayikwazanga ukumataniswa ne <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ngenxa ye-PIN noma isihluthulelo sokungena okungafanele."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Ayaikwazi ukuxhumana ne- <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Ukubhangqa kunqatshelwe i-<xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Ikhompuyutha"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Ama-earphone"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Ifoni"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Ukwenza isithombe"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Amahedfoni"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Okokufaka okulawulwa yikhompuyutha"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"I-Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"I-Wifi ivaliwe."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"I-Wifi inqanyuliwe."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Ibha elilodwa le-Wifi."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"I-Bluetooth Audio LDAC Codec: Ikhwalithi yokudlala"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Khetha i-Bluetooth Audio LDAC Codec:\nIkhwalithi yokudlala"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Ukusakaza: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"I-DNS nge-TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Uma inikwe amandla, zama i-DNS nge-TLS embobeni 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"I-DNS eyimfihlo"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Khetha imodi ye-DNS eyimfihlo"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Kuvaliwe"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Amathuba"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Igama lomsingathi womhlinzeki we-DNS"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Faka igama lomsingathi womhlinzeki we-DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Bonisa izinketho zokunikeza isitifiketi ukubukeka okungenantambo"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"khuphula izinga lokungena le-Wi-Fi, bonisa nge-SSID RSSI engayodwana kusikhethi se-Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Uma inikwe amandla, i-Wi-Fi izoba namandla kakhulu ekudluliseleni ukuxhumeka kwedatha kuselula, uma isignali ye-Wi-Fi iphansi"</string>
@@ -285,6 +296,8 @@
<string name="force_msaa_summary" msgid="9123553203895817537">"Nika amandla i-4x MSAA ezinhlelweni zokusebenza ze-OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Susa iphutha ekusebenzeniokungekhona unxantathu kwesiqeshana"</string>
<string name="track_frame_time" msgid="6146354853663863443">"Iphrofayela ye-GPU iyasebenzeka"</string>
+ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Nika amandla izendlalelo zokususa amaphutha ze-GPU"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Vumela izendlalelo zokususa amaphutha ze-GPU ngezinhlelo zokusebenza zokususa amaphutha"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Iwindi yesilinganisi sesithombe esinyakazayo"</string>
<string name="transition_animation_scale_title" msgid="387527540523595875">"Isilinganiso sesithombe soku"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Isilinganiso sobude besikhathi somenzi womfanekiso onyakazayo"</string>
diff --git a/packages/SettingsLib/res/xml/timezones.xml b/packages/SettingsLib/res/xml/timezones.xml
index 12d31cf..6a8d780 100644
--- a/packages/SettingsLib/res/xml/timezones.xml
+++ b/packages/SettingsLib/res/xml/timezones.xml
@@ -27,6 +27,7 @@
<timezone id="Atlantic/South_Georgia"></timezone>
<timezone id="Atlantic/Azores"></timezone>
<timezone id="Atlantic/Cape_Verde"></timezone>
+ <timezone id="Etc/UTC"></timezone>
<timezone id="Africa/Casablanca"></timezone>
<timezone id="Europe/London"></timezone>
<timezone id="Europe/Amsterdam"></timezone>
diff --git a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
index 2c26410..8055caa 100644
--- a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
@@ -227,7 +227,7 @@
// cache the version code
PackageInfo info = context.getPackageManager().getPackageInfo(
context.getPackageName(), 0);
- sCachedVersionCode = Integer.toString(info.versionCode);
+ sCachedVersionCode = Long.toString(info.getLongVersionCode());
// append the version code to the uri
builder.appendQueryParameter(PARAM_VERSION, sCachedVersionCode);
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 2186169..3c46d99 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -14,8 +14,10 @@
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
+import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.os.BatteryManager;
+import android.os.UserHandle;
import android.os.UserManager;
import android.print.PrintManager;
import android.provider.Settings;
@@ -26,6 +28,10 @@
import java.text.NumberFormat;
public class Utils {
+
+ private static final String CURRENT_MODE_KEY = "CURRENT_MODE";
+ private static final String NEW_MODE_KEY = "NEW_MODE";
+
private static Signature[] sSystemSignature;
private static String sPermissionControllerPackageName;
private static String sServicesSystemSharedLibPackageName;
@@ -39,6 +45,16 @@
com.android.internal.R.drawable.ic_wifi_signal_4
};
+ public static boolean updateLocationMode(Context context, int oldMode, int newMode, int userId) {
+ Intent intent = new Intent(LocationManager.MODE_CHANGING_ACTION);
+ intent.putExtra(CURRENT_MODE_KEY, oldMode);
+ intent.putExtra(NEW_MODE_KEY, newMode);
+ context.sendBroadcastAsUser(
+ intent, UserHandle.of(userId), android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ return Settings.Secure.putIntForUser(
+ context.getContentResolver(), Settings.Secure.LOCATION_MODE, newMode, userId);
+ }
+
/**
* Return string resource that best describes combination of tethering
* options available on this device.
@@ -105,7 +121,8 @@
}
}
return new UserIconDrawable(iconSize).setIconDrawable(
- UserIcons.getDefaultUserIcon(user.id, /* light= */ false)).bake();
+ UserIcons.getDefaultUserIcon(context.getResources(), user.id, /* light= */ false))
+ .bake();
}
/** Formats a double from 0.0..100.0 with an option to round **/
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 5b39ee4..c3ff617 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -118,7 +118,7 @@
public synchronized void clearNonBondedDevices() {
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
- if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
+ if (cachedDevice.getBondState() == BluetoothDevice.BOND_NONE) {
mCachedDevices.remove(i);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java
index ee7885d..0703330 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java
@@ -18,7 +18,6 @@
import android.content.ComponentName;
import android.content.Context;
import android.support.annotation.VisibleForTesting;
-import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -27,7 +26,6 @@
import com.android.settingslib.applications.InterestingConfigChanges;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -104,10 +102,10 @@
}
for (int i = 0; i < mCategories.size(); i++) {
DashboardCategory category = mCategories.get(i);
- for (int j = 0; j < category.tiles.size(); j++) {
- Tile tile = category.tiles.get(j);
+ for (int j = 0; j < category.getTilesCount(); j++) {
+ Tile tile = category.getTile(j);
if (tileBlacklist.contains(tile.intent.getComponent())) {
- category.tiles.remove(j--);
+ category.removeTile(j--);
}
}
}
@@ -181,7 +179,7 @@
newCategory = new DashboardCategory();
categoryByKeyMap.put(newCategoryKey, newCategory);
}
- newCategory.tiles.add(tile);
+ newCategory.addTile(tile);
}
}
}
@@ -198,7 +196,7 @@
synchronized void sortCategories(Context context,
Map<String, DashboardCategory> categoryByKeyMap) {
for (Entry<String, DashboardCategory> categoryEntry : categoryByKeyMap.entrySet()) {
- sortCategoriesForExternalTiles(context, categoryEntry.getValue());
+ categoryEntry.getValue().sortTiles(context.getPackageName());
}
}
@@ -210,16 +208,16 @@
synchronized void filterDuplicateTiles(Map<String, DashboardCategory> categoryByKeyMap) {
for (Entry<String, DashboardCategory> categoryEntry : categoryByKeyMap.entrySet()) {
final DashboardCategory category = categoryEntry.getValue();
- final int count = category.tiles.size();
+ final int count = category.getTilesCount();
final Set<ComponentName> components = new ArraySet<>();
for (int i = count - 1; i >= 0; i--) {
- final Tile tile = category.tiles.get(i);
+ final Tile tile = category.getTile(i);
if (tile.intent == null) {
continue;
}
final ComponentName tileComponent = tile.intent.getComponent();
if (components.contains(tileComponent)) {
- category.tiles.remove(i);
+ category.removeTile(i);
} else {
components.add(tileComponent);
}
@@ -234,28 +232,7 @@
*/
private synchronized void sortCategoriesForExternalTiles(Context context,
DashboardCategory dashboardCategory) {
- final String skipPackageName = context.getPackageName();
+ dashboardCategory.sortTiles(context.getPackageName());
- // Sort tiles based on [priority, package within priority]
- Collections.sort(dashboardCategory.tiles, (tile1, tile2) -> {
- final String package1 = tile1.intent.getComponent().getPackageName();
- final String package2 = tile2.intent.getComponent().getPackageName();
- final int packageCompare = CASE_INSENSITIVE_ORDER.compare(package1, package2);
- // First sort by priority
- final int priorityCompare = tile2.priority - tile1.priority;
- if (priorityCompare != 0) {
- return priorityCompare;
- }
- // Then sort by package name, skip package take precedence
- if (packageCompare != 0) {
- if (TextUtils.equals(package1, skipPackageName)) {
- return -1;
- }
- if (TextUtils.equals(package2, skipPackageName)) {
- return 1;
- }
- }
- return packageCompare;
- });
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
index f6f8168..3a03644 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
@@ -16,6 +16,8 @@
package com.android.settingslib.drawer;
+import static java.lang.String.CASE_INSENSITIVE_ORDER;
+
import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
@@ -23,6 +25,8 @@
import android.util.Log;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
public class DashboardCategory implements Parcelable {
@@ -48,39 +52,63 @@
/**
* List of the category's children
*/
- public List<Tile> tiles = new ArrayList<>();
+ private List<Tile> mTiles = new ArrayList<>();
+ DashboardCategory(DashboardCategory in) {
+ if (in != null) {
+ title = in.title;
+ key = in.key;
+ priority = in.priority;
+ for (Tile tile : in.mTiles) {
+ mTiles.add(tile);
+ }
+ }
+ }
public DashboardCategory() {
// Empty
}
- public void addTile(Tile tile) {
- tiles.add(tile);
+ /**
+ * Get a copy of the list of the category's children.
+ *
+ * Note: the returned list serves as a read-only list. If tiles needs to be added or removed
+ * from the actual tiles list, it should be done through {@link #addTile}, {@link #removeTile}.
+ */
+ public synchronized List<Tile> getTiles() {
+ final List<Tile> result = new ArrayList<>(mTiles.size());
+ for (Tile tile : mTiles) {
+ result.add(tile);
+ }
+ return result;
}
- public void addTile(int n, Tile tile) {
- tiles.add(n, tile);
+ public synchronized void addTile(Tile tile) {
+ mTiles.add(tile);
}
- public void removeTile(Tile tile) {
- tiles.remove(tile);
+ public synchronized void addTile(int n, Tile tile) {
+ mTiles.add(n, tile);
}
- public void removeTile(int n) {
- tiles.remove(n);
+ public synchronized void removeTile(Tile tile) {
+ mTiles.remove(tile);
+ }
+
+ public synchronized void removeTile(int n) {
+ mTiles.remove(n);
}
public int getTilesCount() {
- return tiles.size();
+ return mTiles.size();
}
public Tile getTile(int n) {
- return tiles.get(n);
+ return mTiles.get(n);
}
- public boolean containsComponent(ComponentName component) {
- for (Tile tile : tiles) {
+ public synchronized boolean containsComponent(ComponentName component) {
+ for (Tile tile : mTiles) {
if (TextUtils.equals(tile.intent.getComponent().getClassName(),
component.getClassName())) {
if (DEBUG) {
@@ -95,6 +123,40 @@
return false;
}
+ /**
+ * Sort priority value for tiles in this category.
+ */
+ public void sortTiles() {
+ Collections.sort(mTiles, TILE_COMPARATOR);
+ }
+
+ /**
+ * Sort priority value and package name for tiles in this category.
+ */
+ public synchronized void sortTiles(String skipPackageName) {
+ // Sort mTiles based on [priority, package within priority]
+ Collections.sort(mTiles, (tile1, tile2) -> {
+ final String package1 = tile1.intent.getComponent().getPackageName();
+ final String package2 = tile2.intent.getComponent().getPackageName();
+ final int packageCompare = CASE_INSENSITIVE_ORDER.compare(package1, package2);
+ // First sort by priority
+ final int priorityCompare = tile2.priority - tile1.priority;
+ if (priorityCompare != 0) {
+ return priorityCompare;
+ }
+ // Then sort by package name, skip package take precedence
+ if (packageCompare != 0) {
+ if (TextUtils.equals(package1, skipPackageName)) {
+ return -1;
+ }
+ if (TextUtils.equals(package2, skipPackageName)) {
+ return 1;
+ }
+ }
+ return packageCompare;
+ });
+ }
+
@Override
public int describeContents() {
return 0;
@@ -106,11 +168,11 @@
dest.writeString(key);
dest.writeInt(priority);
- final int count = tiles.size();
+ final int count = mTiles.size();
dest.writeInt(count);
for (int n = 0; n < count; n++) {
- Tile tile = tiles.get(n);
+ Tile tile = mTiles.get(n);
tile.writeToParcel(dest, flags);
}
}
@@ -124,7 +186,7 @@
for (int n = 0; n < count; n++) {
Tile tile = Tile.CREATOR.createFromParcel(in);
- tiles.add(tile);
+ mTiles.add(tile);
}
}
@@ -141,4 +203,13 @@
return new DashboardCategory[size];
}
};
+
+ public static final Comparator<Tile> TILE_COMPARATOR =
+ new Comparator<Tile>() {
+ @Override
+ public int compare(Tile lhs, Tile rhs) {
+ return rhs.priority - lhs.priority;
+ }
+ };
+
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index 038dcf8..e986e0f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -253,7 +253,7 @@
}
ArrayList<DashboardCategory> categories = new ArrayList<>(categoryMap.values());
for (DashboardCategory category : categories) {
- Collections.sort(category.tiles, TILE_COMPARATOR);
+ category.sortTiles();
}
Collections.sort(categories, CATEGORY_COMPARATOR);
if (DEBUG_TIMING) Log.d(LOG_TAG, "getCategories took "
@@ -595,14 +595,6 @@
return pathSegments.get(0);
}
- public static final Comparator<Tile> TILE_COMPARATOR =
- new Comparator<Tile>() {
- @Override
- public int compare(Tile lhs, Tile rhs) {
- return rhs.priority - lhs.priority;
- }
- };
-
private static final Comparator<DashboardCategory> CATEGORY_COMPARATOR =
new Comparator<DashboardCategory>() {
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/UserAdapter.java b/packages/SettingsLib/src/com/android/settingslib/drawer/UserAdapter.java
index b27d823..8a09df2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/UserAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/UserAdapter.java
@@ -64,7 +64,8 @@
if (um.getUserIcon(userId) != null) {
icon = new BitmapDrawable(context.getResources(), um.getUserIcon(userId));
} else {
- icon = UserIcons.getDefaultUserIcon(userId, /* light= */ false);
+ icon = UserIcons.getDefaultUserIcon(
+ context.getResources(), userId, /* light= */ false);
}
}
this.mIcon = encircle(context, icon);
diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java
new file mode 100644
index 0000000..e3e27ce1
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java
@@ -0,0 +1,292 @@
+/*
+ * 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.settingslib.license;
+
+import android.support.annotation.VisibleForTesting;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.zip.GZIPInputStream;
+
+/**
+ * The utility class that generate a license html file from xml files.
+ * All the HTML snippets and logic are copied from build/make/tools/generate-notice-files.py.
+ *
+ * TODO: Remove duplicate codes once backward support ends.
+ */
+class LicenseHtmlGeneratorFromXml {
+ private static final String TAG = "LicenseHtmlGeneratorFromXml";
+
+ private static final String TAG_ROOT = "licenses";
+ private static final String TAG_FILE_NAME = "file-name";
+ private static final String TAG_FILE_CONTENT = "file-content";
+ private static final String ATTR_CONTENT_ID = "contentId";
+
+ private static final String HTML_HEAD_STRING =
+ "<html><head>\n"
+ + "<style type=\"text/css\">\n"
+ + "body { padding: 0; font-family: sans-serif; }\n"
+ + ".same-license { background-color: #eeeeee;\n"
+ + " border-top: 20px solid white;\n"
+ + " padding: 10px; }\n"
+ + ".label { font-weight: bold; }\n"
+ + ".file-list { margin-left: 1em; color: blue; }\n"
+ + "</style>\n"
+ + "</head>"
+ + "<body topmargin=\"0\" leftmargin=\"0\" rightmargin=\"0\" bottommargin=\"0\">\n"
+ + "<div class=\"toc\">\n"
+ + "<ul>";
+
+ private static final String HTML_MIDDLE_STRING =
+ "</ul>\n"
+ + "</div><!-- table of contents -->\n"
+ + "<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\">";
+
+ private static final String HTML_REAR_STRING =
+ "</table></body></html>";
+
+ private final List<File> mXmlFiles;
+
+ /*
+ * A map from a file name to a content id (MD5 sum of file content) for its license.
+ * For example, "/system/priv-app/TeleService/TeleService.apk" maps to
+ * "9645f39e9db895a4aa6e02cb57294595". Here "9645f39e9db895a4aa6e02cb57294595" is a MD5 sum
+ * of the content of packages/services/Telephony/MODULE_LICENSE_APACHE2.
+ */
+ private final Map<String, String> mFileNameToContentIdMap = new HashMap();
+
+ /*
+ * A map from a content id (MD5 sum of file content) to a license file content.
+ * For example, "9645f39e9db895a4aa6e02cb57294595" maps to the content string of
+ * packages/services/Telephony/MODULE_LICENSE_APACHE2. Here "9645f39e9db895a4aa6e02cb57294595"
+ * is a MD5 sum of the file content.
+ */
+ private final Map<String, String> mContentIdToFileContentMap = new HashMap();
+
+ static class ContentIdAndFileNames {
+ final String mContentId;
+ final List<String> mFileNameList = new ArrayList();
+
+ ContentIdAndFileNames(String contentId) {
+ mContentId = contentId;
+ }
+ }
+
+ private LicenseHtmlGeneratorFromXml(List<File> xmlFiles) {
+ mXmlFiles = xmlFiles;
+ }
+
+ public static boolean generateHtml(List<File> xmlFiles, File outputFile) {
+ LicenseHtmlGeneratorFromXml genertor = new LicenseHtmlGeneratorFromXml(xmlFiles);
+ return genertor.generateHtml(outputFile);
+ }
+
+ private boolean generateHtml(File outputFile) {
+ for (File xmlFile : mXmlFiles) {
+ parse(xmlFile);
+ }
+
+ if (mFileNameToContentIdMap.isEmpty() || mContentIdToFileContentMap.isEmpty()) {
+ return false;
+ }
+
+ PrintWriter writer = null;
+ try {
+ writer = new PrintWriter(outputFile);
+
+ generateHtml(mFileNameToContentIdMap, mContentIdToFileContentMap, writer);
+
+ writer.flush();
+ writer.close();
+ return true;
+ } catch (FileNotFoundException | SecurityException e) {
+ Log.e(TAG, "Failed to generate " + outputFile, e);
+
+ if (writer != null) {
+ writer.close();
+ }
+ return false;
+ }
+ }
+
+ private void parse(File xmlFile) {
+ if (xmlFile == null || !xmlFile.exists() || xmlFile.length() == 0) {
+ return;
+ }
+
+ InputStreamReader in = null;
+ try {
+ if (xmlFile.getName().endsWith(".gz")) {
+ in = new InputStreamReader(new GZIPInputStream(new FileInputStream(xmlFile)));
+ } else {
+ in = new FileReader(xmlFile);
+ }
+
+ parse(in, mFileNameToContentIdMap, mContentIdToFileContentMap);
+
+ in.close();
+ } catch (XmlPullParserException | IOException e) {
+ Log.e(TAG, "Failed to parse " + xmlFile, e);
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException ie) {
+ Log.w(TAG, "Failed to close " + xmlFile);
+ }
+ }
+ }
+ }
+
+ /*
+ * Parses an input stream and fills a map from a file name to a content id for its license
+ * and a map from a content id to a license file content.
+ *
+ * Following xml format is expected from the input stream.
+ *
+ * <licenses>
+ * <file-name contentId="content_id_of_license1">file1</file-name>
+ * <file-name contentId="content_id_of_license2">file2</file-name>
+ * ...
+ * <file-content contentId="content_id_of_license1">license1 file contents</file-content>
+ * <file-content contentId="content_id_of_license2">license2 file contents</file-content>
+ * ...
+ * </licenses>
+ */
+ @VisibleForTesting
+ static void parse(InputStreamReader in, Map<String, String> outFileNameToContentIdMap,
+ Map<String, String> outContentIdToFileContentMap)
+ throws XmlPullParserException, IOException {
+ Map<String, String> fileNameToContentIdMap = new HashMap<String, String>();
+ Map<String, String> contentIdToFileContentMap = new HashMap<String, String>();
+
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in);
+ parser.nextTag();
+
+ parser.require(XmlPullParser.START_TAG, "", TAG_ROOT);
+
+ int state = parser.getEventType();
+ while (state != XmlPullParser.END_DOCUMENT) {
+ if (state == XmlPullParser.START_TAG) {
+ if (TAG_FILE_NAME.equals(parser.getName())) {
+ String contentId = parser.getAttributeValue("", ATTR_CONTENT_ID);
+ if (!TextUtils.isEmpty(contentId)) {
+ String fileName = readText(parser).trim();
+ if (!TextUtils.isEmpty(fileName)) {
+ fileNameToContentIdMap.put(fileName, contentId);
+ }
+ }
+ } else if (TAG_FILE_CONTENT.equals(parser.getName())) {
+ String contentId = parser.getAttributeValue("", ATTR_CONTENT_ID);
+ if (!TextUtils.isEmpty(contentId)
+ && !outContentIdToFileContentMap.containsKey(contentId)
+ && !contentIdToFileContentMap.containsKey(contentId)) {
+ String fileContent = readText(parser);
+ if (!TextUtils.isEmpty(fileContent)) {
+ contentIdToFileContentMap.put(contentId, fileContent);
+ }
+ }
+ }
+ }
+
+ state = parser.next();
+ }
+ outFileNameToContentIdMap.putAll(fileNameToContentIdMap);
+ outContentIdToFileContentMap.putAll(contentIdToFileContentMap);
+ }
+
+ private static String readText(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ StringBuffer result = new StringBuffer();
+ int state = parser.next();
+ while (state == XmlPullParser.TEXT) {
+ result.append(parser.getText());
+ state = parser.next();
+ }
+ return result.toString();
+ }
+
+ @VisibleForTesting
+ static void generateHtml(Map<String, String> fileNameToContentIdMap,
+ Map<String, String> contentIdToFileContentMap, PrintWriter writer) {
+ List<String> fileNameList = new ArrayList();
+ fileNameList.addAll(fileNameToContentIdMap.keySet());
+ Collections.sort(fileNameList);
+
+ writer.println(HTML_HEAD_STRING);
+
+ int count = 0;
+ Map<String, Integer> contentIdToOrderMap = new HashMap();
+ List<ContentIdAndFileNames> contentIdAndFileNamesList = new ArrayList();
+
+ // Prints all the file list with a link to its license file content.
+ for (String fileName : fileNameList) {
+ String contentId = fileNameToContentIdMap.get(fileName);
+ // Assigns an id to a newly referred license file content.
+ if (!contentIdToOrderMap.containsKey(contentId)) {
+ contentIdToOrderMap.put(contentId, count);
+
+ // An index in contentIdAndFileNamesList is the order of each element.
+ contentIdAndFileNamesList.add(new ContentIdAndFileNames(contentId));
+ count++;
+ }
+
+ int id = contentIdToOrderMap.get(contentId);
+ contentIdAndFileNamesList.get(id).mFileNameList.add(fileName);
+ writer.format("<li><a href=\"#id%d\">%s</a></li>\n", id, fileName);
+ }
+
+ writer.println(HTML_MIDDLE_STRING);
+
+ count = 0;
+ // Prints all contents of the license files in order of id.
+ for (ContentIdAndFileNames contentIdAndFileNames : contentIdAndFileNamesList) {
+ writer.format("<tr id=\"id%d\"><td class=\"same-license\">\n", count);
+ writer.println("<div class=\"label\">Notices for file(s):</div>");
+ writer.println("<div class=\"file-list\">");
+ for (String fileName : contentIdAndFileNames.mFileNameList) {
+ writer.format("%s <br/>\n", fileName);
+ }
+ writer.println("</div><!-- file-list -->");
+ writer.println("<pre class=\"license-text\">");
+ writer.println(contentIdToFileContentMap.get(
+ contentIdAndFileNames.mContentId));
+ writer.println("</pre><!-- license-text -->");
+ writer.println("</td></tr><!-- same-license -->");
+
+ count++;
+ }
+
+ writer.println(HTML_REAR_STRING);
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java
new file mode 100644
index 0000000..a9fb20c
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java
@@ -0,0 +1,110 @@
+/*
+ * 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.settingslib.license;
+
+import android.content.Context;
+import android.support.annotation.VisibleForTesting;
+import android.util.Log;
+
+import com.android.settingslib.utils.AsyncLoader;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * LicenseHtmlLoader is a loader which loads a license html file from default license xml files.
+ */
+public class LicenseHtmlLoader extends AsyncLoader<File> {
+ private static final String TAG = "LicenseHtmlLoader";
+
+ private static final String[] DEFAULT_LICENSE_XML_PATHS = {
+ "/system/etc/NOTICE.xml.gz",
+ "/vendor/etc/NOTICE.xml.gz",
+ "/odm/etc/NOTICE.xml.gz",
+ "/oem/etc/NOTICE.xml.gz"};
+ private static final String NOTICE_HTML_FILE_NAME = "NOTICE.html";
+
+ private Context mContext;
+
+ public LicenseHtmlLoader(Context context) {
+ super(context);
+ mContext = context;
+ }
+
+ @Override
+ public File loadInBackground() {
+ return generateHtmlFromDefaultXmlFiles();
+ }
+
+ @Override
+ protected void onDiscardResult(File f) {
+ }
+
+ private File generateHtmlFromDefaultXmlFiles() {
+ final List<File> xmlFiles = getVaildXmlFiles();
+ if (xmlFiles.isEmpty()) {
+ Log.e(TAG, "No notice file exists.");
+ return null;
+ }
+
+ File cachedHtmlFile = getCachedHtmlFile();
+ if (!isCachedHtmlFileOutdated(xmlFiles, cachedHtmlFile)
+ || generateHtmlFile(xmlFiles, cachedHtmlFile)) {
+ return cachedHtmlFile;
+ }
+
+ return null;
+ }
+
+ @VisibleForTesting
+ List<File> getVaildXmlFiles() {
+ final List<File> xmlFiles = new ArrayList();
+ for (final String xmlPath : DEFAULT_LICENSE_XML_PATHS) {
+ File file = new File(xmlPath);
+ if (file.exists() && file.length() != 0) {
+ xmlFiles.add(file);
+ }
+ }
+ return xmlFiles;
+ }
+
+ @VisibleForTesting
+ File getCachedHtmlFile() {
+ return new File(mContext.getCacheDir(), NOTICE_HTML_FILE_NAME);
+ }
+
+ @VisibleForTesting
+ boolean isCachedHtmlFileOutdated(List<File> xmlFiles, File cachedHtmlFile) {
+ boolean outdated = true;
+ if (cachedHtmlFile.exists() && cachedHtmlFile.length() != 0) {
+ outdated = false;
+ for (File file : xmlFiles) {
+ if (cachedHtmlFile.lastModified() < file.lastModified()) {
+ outdated = true;
+ break;
+ }
+ }
+ }
+ return outdated;
+ }
+
+ @VisibleForTesting
+ boolean generateHtmlFile(List<File> xmlFiles, File htmlFile) {
+ return LicenseHtmlGeneratorFromXml.generateHtml(xmlFiles, htmlFile);
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/AsyncLoader.java b/packages/SettingsLib/src/com/android/settingslib/utils/AsyncLoader.java
new file mode 100644
index 0000000..06770ac
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/AsyncLoader.java
@@ -0,0 +1,110 @@
+/*
+ * 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.settingslib.utils;
+
+import android.content.AsyncTaskLoader;
+import android.content.Context;
+
+/**
+ * This class fills in some boilerplate for AsyncTaskLoader to actually load things.
+ *
+ * Subclasses need to implement {@link AsyncLoader#loadInBackground()} to perform the actual
+ * background task, and {@link AsyncLoader#onDiscardResult(T)} to clean up previously loaded
+ * results.
+ *
+ * This loader is based on the MailAsyncTaskLoader from the AOSP EmailUnified repo.
+ *
+ * @param <T> the data type to be loaded.
+ */
+public abstract class AsyncLoader<T> extends AsyncTaskLoader<T> {
+ private T mResult;
+
+ public AsyncLoader(final Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onStartLoading() {
+ if (mResult != null) {
+ deliverResult(mResult);
+ }
+
+ if (takeContentChanged() || mResult == null) {
+ forceLoad();
+ }
+ }
+
+ @Override
+ protected void onStopLoading() {
+ cancelLoad();
+ }
+
+ @Override
+ public void deliverResult(final T data) {
+ if (isReset()) {
+ if (data != null) {
+ onDiscardResult(data);
+ }
+ return;
+ }
+
+ final T oldResult = mResult;
+ mResult = data;
+
+ if (isStarted()) {
+ super.deliverResult(data);
+ }
+
+ if (oldResult != null && oldResult != mResult) {
+ onDiscardResult(oldResult);
+ }
+ }
+
+ @Override
+ protected void onReset() {
+ super.onReset();
+
+ onStopLoading();
+
+ if (mResult != null) {
+ onDiscardResult(mResult);
+ }
+ mResult = null;
+ }
+
+ @Override
+ public void onCanceled(final T data) {
+ super.onCanceled(data);
+
+ if (data != null) {
+ onDiscardResult(data);
+ }
+ }
+
+ /**
+ * Called when discarding the load results so subclasses can take care of clean-up or
+ * recycling tasks. This is not called if the same result (by way of pointer equality) is
+ * returned again by a subsequent call to loadInBackground, or if result is null.
+ *
+ * Note that this may be called concurrently with loadInBackground(), and in some circumstances
+ * may be called more than once for a given object.
+ *
+ * @param result The value returned from {@link AsyncLoader#loadInBackground()} which
+ * is to be discarded.
+ */
+ protected abstract void onDiscardResult(T result);
+}
diff --git a/packages/SettingsLib/tests/integ/Android.mk b/packages/SettingsLib/tests/integ/Android.mk
index 7ace048..3c8c8ac 100644
--- a/packages/SettingsLib/tests/integ/Android.mk
+++ b/packages/SettingsLib/tests/integ/Android.mk
@@ -27,6 +27,8 @@
LOCAL_PACKAGE_NAME := SettingsLibTests
LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_USE_AAPT2 := true
+
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
espresso-core \
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
index 820231e..85b04c8 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
@@ -159,14 +159,14 @@
for (String pkg : defaultImes) {
final ResolveInfo ri = createResolveInfoForSystemApp(pkg);
final InputMethodInfo inputMethodInfo = new InputMethodInfo(
- ri, false, null, null, 0, true, true);
+ ri, false, null, null, 0, true, true, false);
inputMethods.add(inputMethodInfo);
addInstalledApp(ri);
}
for (String pkg : otherImes) {
final ResolveInfo ri = createResolveInfoForSystemApp(pkg);
final InputMethodInfo inputMethodInfo = new InputMethodInfo(
- ri, false, null, null, 0, false, true);
+ ri, false, null, null, 0, false, true, false);
inputMethods.add(inputMethodInfo);
addInstalledApp(ri);
}
diff --git a/packages/SettingsLib/tests/robotests/Android.mk b/packages/SettingsLib/tests/robotests/Android.mk
index bc1a834..2738027 100644
--- a/packages/SettingsLib/tests/robotests/Android.mk
+++ b/packages/SettingsLib/tests/robotests/Android.mk
@@ -28,6 +28,8 @@
LOCAL_RESOURCE_DIR := \
$(LOCAL_PATH)/res
+LOCAL_USE_AAPT2 := true
+
include frameworks/base/packages/SettingsLib/common.mk
include $(BUILD_PACKAGE)
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index c6cfdb8..976bbee 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -15,20 +15,45 @@
*/
package com.android.settingslib;
+import android.app.ActivityManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.location.LocationManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.text.TextUtils;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+import org.mockito.ArgumentMatchers;
+import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Matchers.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.content.res.Resources;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowSettings;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+@Config(
+ manifest = TestConfig.MANIFEST_PATH,
+ sdk = TestConfig.SDK_VERSION,
+ shadows = {UtilsTest.ShadowSecure.class})
public class UtilsTest {
private static final double[] TEST_PERCENTAGES = {0, 0.4, 0.5, 0.6, 49, 49.3, 49.8, 50, 100};
private static final String PERCENTAGE_0 = "0%";
@@ -37,6 +62,29 @@
private static final String PERCENTAGE_50 = "50%";
private static final String PERCENTAGE_100 = "100%";
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mContext = spy(RuntimeEnvironment.application);
+ ShadowSecure.reset();
+ }
+
+ @Test
+ public void testUpdateLocationMode_sendBroadcast() {
+ int currentUserId = ActivityManager.getCurrentUser();
+ Utils.updateLocationMode(
+ mContext,
+ Secure.LOCATION_MODE_OFF,
+ Secure.LOCATION_MODE_HIGH_ACCURACY,
+ currentUserId);
+
+ verify(mContext).sendBroadcastAsUser(
+ argThat(actionMatches(LocationManager.MODE_CHANGING_ACTION)),
+ ArgumentMatchers.eq(UserHandle.of(currentUserId)),
+ ArgumentMatchers.eq(WRITE_SECURE_SETTINGS));
+ }
+
@Test
public void testFormatPercentage_RoundTrue_RoundUpIfPossible() {
final String[] expectedPercentages = {PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_1,
@@ -74,4 +122,23 @@
.thenReturn(60);
assertThat(Utils.getDefaultStorageManagerDaysToRetain(resources)).isEqualTo(60);
}
+
+ private static ArgumentMatcher<Intent> actionMatches(String expected) {
+ return intent -> TextUtils.equals(expected, intent.getAction());
+ }
+
+ @Implements(value = Settings.Secure.class)
+ public static class ShadowSecure extends ShadowSettings.ShadowSecure {
+ private static Map<String, Integer> map = new HashMap<>();
+
+ @Implementation
+ public static boolean putIntForUser(ContentResolver cr, String name, int value, int userHandle) {
+ map.put(name, value);
+ return true;
+ }
+
+ public static void reset() {
+ map.clear();
+ }
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java
index d7eae5f..f099c90 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java
@@ -95,8 +95,9 @@
mCategoryManager.backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
assertThat(mCategoryByKeyMap.size()).isEqualTo(2);
- assertThat(mCategoryByKeyMap.get(CategoryKey.CATEGORY_ACCOUNT).tiles.size()).isEqualTo(1);
- assertThat(mCategoryByKeyMap.get(oldCategory).tiles.size()).isEqualTo(1);
+ assertThat(
+ mCategoryByKeyMap.get(CategoryKey.CATEGORY_ACCOUNT).getTilesCount()).isEqualTo(1);
+ assertThat(mCategoryByKeyMap.get(oldCategory).getTilesCount()).isEqualTo(1);
}
@Test
@@ -114,9 +115,10 @@
// Added 1 more category to category map.
assertThat(mCategoryByKeyMap.size()).isEqualTo(2);
// The new category map has CATEGORY_NETWORK type now, which contains 1 tile.
- assertThat(mCategoryByKeyMap.get(CategoryKey.CATEGORY_NETWORK).tiles.size()).isEqualTo(1);
+ assertThat(
+ mCategoryByKeyMap.get(CategoryKey.CATEGORY_NETWORK).getTilesCount()).isEqualTo(1);
// Old category still exists.
- assertThat(mCategoryByKeyMap.get(oldCategory).tiles.size()).isEqualTo(1);
+ assertThat(mCategoryByKeyMap.get(oldCategory).getTilesCount()).isEqualTo(1);
}
@Test
@@ -136,9 +138,9 @@
tile3.intent =
new Intent().setComponent(new ComponentName(testPackage, "class3"));
tile3.priority = 200;
- category.tiles.add(tile1);
- category.tiles.add(tile2);
- category.tiles.add(tile3);
+ category.addTile(tile1);
+ category.addTile(tile2);
+ category.addTile(tile3);
mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
// Sort their priorities
@@ -146,9 +148,9 @@
mCategoryByKeyMap);
// Verify they are now sorted.
- assertThat(category.tiles.get(0)).isSameAs(tile3);
- assertThat(category.tiles.get(1)).isSameAs(tile1);
- assertThat(category.tiles.get(2)).isSameAs(tile2);
+ assertThat(category.getTile(0)).isSameAs(tile3);
+ assertThat(category.getTile(1)).isSameAs(tile1);
+ assertThat(category.getTile(2)).isSameAs(tile2);
}
@Test
@@ -169,9 +171,9 @@
tile3.intent =
new Intent().setComponent(new ComponentName(testPackage1, "class3"));
tile3.priority = 50;
- category.tiles.add(tile1);
- category.tiles.add(tile2);
- category.tiles.add(tile3);
+ category.addTile(tile1);
+ category.addTile(tile2);
+ category.addTile(tile3);
mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
// Sort their priorities
@@ -179,9 +181,9 @@
mCategoryByKeyMap);
// Verify they are now sorted.
- assertThat(category.tiles.get(0)).isSameAs(tile2);
- assertThat(category.tiles.get(1)).isSameAs(tile1);
- assertThat(category.tiles.get(2)).isSameAs(tile3);
+ assertThat(category.getTile(0)).isSameAs(tile2);
+ assertThat(category.getTile(1)).isSameAs(tile1);
+ assertThat(category.getTile(2)).isSameAs(tile3);
}
@Test
@@ -202,9 +204,9 @@
tile3.intent =
new Intent().setComponent(new ComponentName(testPackage, "class3"));
tile3.priority = 50;
- category.tiles.add(tile1);
- category.tiles.add(tile2);
- category.tiles.add(tile3);
+ category.addTile(tile1);
+ category.addTile(tile2);
+ category.addTile(tile3);
mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
// Sort their priorities
@@ -212,9 +214,9 @@
mCategoryByKeyMap);
// Verify the sorting order is not changed
- assertThat(category.tiles.get(0)).isSameAs(tile1);
- assertThat(category.tiles.get(1)).isSameAs(tile2);
- assertThat(category.tiles.get(2)).isSameAs(tile3);
+ assertThat(category.getTile(0)).isSameAs(tile1);
+ assertThat(category.getTile(1)).isSameAs(tile2);
+ assertThat(category.getTile(2)).isSameAs(tile3);
}
@Test
@@ -236,10 +238,10 @@
final Tile tile4 = new Tile();
tile4.intent = new Intent().setComponent(new ComponentName(testPackage, "class3"));
tile4.priority = -1;
- category.tiles.add(tile1);
- category.tiles.add(tile2);
- category.tiles.add(tile3);
- category.tiles.add(tile4);
+ category.addTile(tile1);
+ category.addTile(tile2);
+ category.addTile(tile3);
+ category.addTile(tile4);
mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
// Sort their priorities
@@ -247,10 +249,10 @@
mCategoryByKeyMap);
// Verify the sorting order is not changed
- assertThat(category.tiles.get(0)).isSameAs(tile1);
- assertThat(category.tiles.get(1)).isSameAs(tile2);
- assertThat(category.tiles.get(2)).isSameAs(tile3);
- assertThat(category.tiles.get(3)).isSameAs(tile4);
+ assertThat(category.getTile(0)).isSameAs(tile1);
+ assertThat(category.getTile(1)).isSameAs(tile2);
+ assertThat(category.getTile(2)).isSameAs(tile3);
+ assertThat(category.getTile(3)).isSameAs(tile4);
}
@Test
@@ -270,9 +272,9 @@
final Tile tile3 = new Tile();
tile3.intent = new Intent().setComponent(new ComponentName(testPackage3, "class3"));
tile3.priority = 1;
- category.tiles.add(tile1);
- category.tiles.add(tile2);
- category.tiles.add(tile3);
+ category.addTile(tile1);
+ category.addTile(tile2);
+ category.addTile(tile3);
mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
// Sort their priorities
@@ -280,9 +282,9 @@
mCategoryByKeyMap);
// Verify the sorting order is internal first, follow by package name ordering
- assertThat(category.tiles.get(0)).isSameAs(tile2);
- assertThat(category.tiles.get(1)).isSameAs(tile3);
- assertThat(category.tiles.get(2)).isSameAs(tile1);
+ assertThat(category.getTile(0)).isSameAs(tile2);
+ assertThat(category.getTile(1)).isSameAs(tile3);
+ assertThat(category.getTile(2)).isSameAs(tile1);
}
@Test
@@ -303,14 +305,14 @@
tile3.intent =
new Intent().setComponent(new ComponentName(testPackage, "class3"));
tile3.priority = 50;
- category.tiles.add(tile1);
- category.tiles.add(tile2);
- category.tiles.add(tile3);
+ category.addTile(tile1);
+ category.addTile(tile2);
+ category.addTile(tile3);
mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
mCategoryManager.filterDuplicateTiles(mCategoryByKeyMap);
- assertThat(category.tiles.size()).isEqualTo(3);
+ assertThat(category.getTilesCount()).isEqualTo(3);
}
@Test
@@ -331,13 +333,13 @@
tile3.intent =
new Intent().setComponent(new ComponentName(testPackage, "class1"));
tile3.priority = 50;
- category.tiles.add(tile1);
- category.tiles.add(tile2);
- category.tiles.add(tile3);
+ category.addTile(tile1);
+ category.addTile(tile2);
+ category.addTile(tile3);
mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
mCategoryManager.filterDuplicateTiles(mCategoryByKeyMap);
- assertThat(category.tiles.size()).isEqualTo(1);
+ assertThat(category.getTilesCount()).isEqualTo(1);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index dad3a28..a395a4a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -216,7 +216,7 @@
List<DashboardCategory> categoryList = TileUtils.getCategories(
mContext, cache, false /* categoryDefinedInManifest */, testAction,
TileUtils.SETTING_PKG);
- assertThat(categoryList.get(0).tiles.get(0).category).isEqualTo(testCategory);
+ assertThat(categoryList.get(0).getTile(0).category).isEqualTo(testCategory);
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
new file mode 100644
index 0000000..c7e9262
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.settingslib.license;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.android.settingslib.TestConfig;
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class LicenseHtmlGeneratorFromXmlTest {
+ private static final String VALILD_XML_STRING =
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ + "<licenses>\n"
+ + "<file-name contentId=\"0\">/file0</file-name>\n"
+ + "<file-name contentId=\"0\">/file1</file-name>\n"
+ + "<file-content contentId=\"0\"><![CDATA[license content #0]]></file-content>\n"
+ + "</licenses>";
+
+ private static final String INVALILD_XML_STRING =
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ + "<licenses2>\n"
+ + "<file-name contentId=\"0\">/file0</file-name>\n"
+ + "<file-name contentId=\"0\">/file1</file-name>\n"
+ + "<file-content contentId=\"0\"><![CDATA[license content #0]]></file-content>\n"
+ + "</licenses2>";
+
+ private static final String EXPECTED_HTML_STRING =
+ "<html><head>\n"
+ + "<style type=\"text/css\">\n"
+ + "body { padding: 0; font-family: sans-serif; }\n"
+ + ".same-license { background-color: #eeeeee;\n"
+ + " border-top: 20px solid white;\n"
+ + " padding: 10px; }\n"
+ + ".label { font-weight: bold; }\n"
+ + ".file-list { margin-left: 1em; color: blue; }\n"
+ + "</style>\n"
+ + "</head>"
+ + "<body topmargin=\"0\" leftmargin=\"0\" rightmargin=\"0\" bottommargin=\"0\">\n"
+ + "<div class=\"toc\">\n"
+ + "<ul>\n"
+ + "<li><a href=\"#id0\">/file0</a></li>\n"
+ + "<li><a href=\"#id0\">/file1</a></li>\n"
+ + "</ul>\n"
+ + "</div><!-- table of contents -->\n"
+ + "<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n"
+ + "<tr id=\"id0\"><td class=\"same-license\">\n"
+ + "<div class=\"label\">Notices for file(s):</div>\n"
+ + "<div class=\"file-list\">\n"
+ + "/file0 <br/>\n"
+ + "/file1 <br/>\n"
+ + "</div><!-- file-list -->\n"
+ + "<pre class=\"license-text\">\n"
+ + "license content #0\n"
+ + "</pre><!-- license-text -->\n"
+ + "</td></tr><!-- same-license -->\n"
+ + "</table></body></html>\n";
+
+ @Test
+ public void testParseValidXmlStream() throws XmlPullParserException, IOException {
+ Map<String, String> fileNameToContentIdMap = new HashMap<String, String>();
+ Map<String, String> contentIdToFileContentMap = new HashMap<String, String>();
+
+ LicenseHtmlGeneratorFromXml.parse(
+ new InputStreamReader(new ByteArrayInputStream(VALILD_XML_STRING.getBytes())),
+ fileNameToContentIdMap, contentIdToFileContentMap);
+ assertThat(fileNameToContentIdMap.size()).isEqualTo(2);
+ assertThat(fileNameToContentIdMap.get("/file0")).isEqualTo("0");
+ assertThat(fileNameToContentIdMap.get("/file1")).isEqualTo("0");
+ assertThat(contentIdToFileContentMap.size()).isEqualTo(1);
+ assertThat(contentIdToFileContentMap.get("0")).isEqualTo("license content #0");
+ }
+
+ @Test(expected = XmlPullParserException.class)
+ public void testParseInvalidXmlStream() throws XmlPullParserException, IOException {
+ Map<String, String> fileNameToContentIdMap = new HashMap<String, String>();
+ Map<String, String> contentIdToFileContentMap = new HashMap<String, String>();
+
+ LicenseHtmlGeneratorFromXml.parse(
+ new InputStreamReader(new ByteArrayInputStream(INVALILD_XML_STRING.getBytes())),
+ fileNameToContentIdMap, contentIdToFileContentMap);
+ }
+
+ @Test
+ public void testGenerateHtml() {
+ Map<String, String> fileNameToContentIdMap = new HashMap<String, String>();
+ Map<String, String> contentIdToFileContentMap = new HashMap<String, String>();
+
+ fileNameToContentIdMap.put("/file0", "0");
+ fileNameToContentIdMap.put("/file1", "0");
+ contentIdToFileContentMap.put("0", "license content #0");
+
+ StringWriter output = new StringWriter();
+ LicenseHtmlGeneratorFromXml.generateHtml(
+ fileNameToContentIdMap, contentIdToFileContentMap, new PrintWriter(output));
+ assertThat(output.toString()).isEqualTo(EXPECTED_HTML_STRING);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderTest.java
new file mode 100644
index 0000000..1a6f30c
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.settingslib.license;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+
+import com.android.settingslib.TestConfig;
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import java.io.File;
+import java.util.ArrayList;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class LicenseHtmlLoaderTest {
+ @Mock
+ private Context mContext;
+
+ LicenseHtmlLoader newLicenseHtmlLoader(ArrayList<File> xmlFiles,
+ File cachedHtmlFile, boolean isCachedHtmlFileOutdated,
+ boolean generateHtmlFileSucceeded) {
+ LicenseHtmlLoader loader = spy(new LicenseHtmlLoader(mContext));
+ doReturn(xmlFiles).when(loader).getVaildXmlFiles();
+ doReturn(cachedHtmlFile).when(loader).getCachedHtmlFile();
+ doReturn(isCachedHtmlFileOutdated).when(loader).isCachedHtmlFileOutdated(any(), any());
+ doReturn(generateHtmlFileSucceeded).when(loader).generateHtmlFile(any(), any());
+ return loader;
+ }
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testLoadInBackground() {
+ ArrayList<File> xmlFiles = new ArrayList();
+ xmlFiles.add(new File("test.xml"));
+ File cachedHtmlFile = new File("test.html");
+
+ LicenseHtmlLoader loader = newLicenseHtmlLoader(xmlFiles, cachedHtmlFile, true, true);
+
+ assertThat(loader.loadInBackground()).isEqualTo(cachedHtmlFile);
+ verify(loader).generateHtmlFile(any(), any());
+ }
+
+ @Test
+ public void testLoadInBackgroundWithNoVaildXmlFiles() {
+ ArrayList<File> xmlFiles = new ArrayList();
+ File cachedHtmlFile = new File("test.html");
+
+ LicenseHtmlLoader loader = newLicenseHtmlLoader(xmlFiles, cachedHtmlFile, true, true);
+
+ assertThat(loader.loadInBackground()).isNull();
+ verify(loader, never()).generateHtmlFile(any(), any());
+ }
+
+ @Test
+ public void testLoadInBackgroundWithNonOutdatedCachedHtmlFile() {
+ ArrayList<File> xmlFiles = new ArrayList();
+ xmlFiles.add(new File("test.xml"));
+ File cachedHtmlFile = new File("test.html");
+
+ LicenseHtmlLoader loader = newLicenseHtmlLoader(xmlFiles, cachedHtmlFile, false, true);
+
+ assertThat(loader.loadInBackground()).isEqualTo(cachedHtmlFile);
+ verify(loader, never()).generateHtmlFile(any(), any());
+ }
+
+ @Test
+ public void testLoadInBackgroundWithGenerateHtmlFileFailed() {
+ ArrayList<File> xmlFiles = new ArrayList();
+ xmlFiles.add(new File("test.xml"));
+ File cachedHtmlFile = new File("test.html");
+
+ LicenseHtmlLoader loader = newLicenseHtmlLoader(xmlFiles, cachedHtmlFile, true, false);
+
+ assertThat(loader.loadInBackground()).isNull();
+ verify(loader).generateHtmlFile(any(), any());
+ }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index ba1c9e3..fabdbd4 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -801,6 +801,9 @@
Settings.Global.BLUETOOTH_PAN_PRIORITY_PREFIX,
GlobalSettingsProto.BLUETOOTH_PAN_PRIORITY_PREFIX);
dumpSetting(s, p,
+ Settings.Global.BLUETOOTH_HEARING_AID_PRIORITY_PREFIX,
+ GlobalSettingsProto.BLUETOOTH_HEARING_AID_PRIORITY_PREFIX);
+ dumpSetting(s, p,
Settings.Global.ACTIVITY_MANAGER_CONSTANTS,
GlobalSettingsProto.ACTIVITY_MANAGER_CONSTANTS);
dumpSetting(s, p,
@@ -1054,9 +1057,6 @@
Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED,
GlobalSettingsProto.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED);
dumpSetting(s, p,
- Settings.Global.BACKUP_REFACTORED_SERVICE_DISABLED,
- GlobalSettingsProto.BACKUP_REFACTORED_SERVICE_DISABLED);
- dumpSetting(s, p,
Settings.Global.EUICC_FACTORY_RESET_TIMEOUT_MILLIS,
GlobalSettingsProto.EUICC_FACTORY_RESET_TIMEOUT_MILLIS);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 258c96c..f4ec936 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -61,6 +61,7 @@
import android.os.UserManagerInternal;
import android.provider.Settings;
import android.provider.Settings.Global;
+import android.provider.Settings.Secure;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -173,13 +174,10 @@
Settings.NameValueTable.VALUE
};
- public static final int SETTINGS_TYPE_GLOBAL = 0;
- public static final int SETTINGS_TYPE_SYSTEM = 1;
- public static final int SETTINGS_TYPE_SECURE = 2;
- public static final int SETTINGS_TYPE_SSAID = 3;
-
- public static final int SETTINGS_TYPE_MASK = 0xF0000000;
- public static final int SETTINGS_TYPE_SHIFT = 28;
+ public static final int SETTINGS_TYPE_GLOBAL = SettingsState.SETTINGS_TYPE_GLOBAL;
+ public static final int SETTINGS_TYPE_SYSTEM = SettingsState.SETTINGS_TYPE_SYSTEM;
+ public static final int SETTINGS_TYPE_SECURE = SettingsState.SETTINGS_TYPE_SECURE;
+ public static final int SETTINGS_TYPE_SSAID = SettingsState.SETTINGS_TYPE_SSAID;
private static final Bundle NULL_SETTING_BUNDLE = Bundle.forPair(
Settings.NameValueTable.VALUE, null);
@@ -277,40 +275,23 @@
private volatile IPackageManager mPackageManager;
public static int makeKey(int type, int userId) {
- return (type << SETTINGS_TYPE_SHIFT) | userId;
+ return SettingsState.makeKey(type, userId);
}
public static int getTypeFromKey(int key) {
- return key >>> SETTINGS_TYPE_SHIFT;
+ return SettingsState.getTypeFromKey(key);
}
public static int getUserIdFromKey(int key) {
- return key & ~SETTINGS_TYPE_MASK;
+ return SettingsState.getUserIdFromKey(key);
}
public static String settingTypeToString(int type) {
- switch (type) {
- case SETTINGS_TYPE_GLOBAL: {
- return "SETTINGS_GLOBAL";
- }
- case SETTINGS_TYPE_SECURE: {
- return "SETTINGS_SECURE";
- }
- case SETTINGS_TYPE_SYSTEM: {
- return "SETTINGS_SYSTEM";
- }
- case SETTINGS_TYPE_SSAID: {
- return "SETTINGS_SSAID";
- }
- default: {
- return "UNKNOWN";
- }
- }
+ return SettingsState.settingTypeToString(type);
}
public static String keyToString(int key) {
- return "Key[user=" + getUserIdFromKey(key) + ";type="
- + settingTypeToString(getTypeFromKey(key)) + "]";
+ return SettingsState.keyToString(key);
}
@Override
@@ -343,7 +324,8 @@
}
case Settings.CALL_METHOD_GET_SECURE: {
- Setting setting = getSecureSetting(name, requestingUserId);
+ Setting setting = getSecureSetting(name, requestingUserId,
+ /*enableOverride=*/ true);
return packageValueForCallResult(setting, isTrackingGeneration(args));
}
@@ -1073,6 +1055,10 @@
}
private Setting getSecureSetting(String name, int requestingUserId) {
+ return getSecureSetting(name, requestingUserId, /*enableOverride=*/ false);
+ }
+
+ private Setting getSecureSetting(String name, int requestingUserId, boolean enableOverride) {
if (DEBUG) {
Slog.v(LOG_TAG, "getSecureSetting(" + name + ", " + requestingUserId + ")");
}
@@ -1102,6 +1088,14 @@
return getSsaidSettingLocked(callingPkg, owningUserId);
}
}
+ if (enableOverride) {
+ if (Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) {
+ final Setting overridden = getLocationProvidersAllowedSetting(owningUserId);
+ if (overridden != null) {
+ return overridden;
+ }
+ }
+ }
// Not the SSAID; do a straight lookup
synchronized (mLock) {
@@ -1190,6 +1184,35 @@
return null;
}
+ private Setting getLocationProvidersAllowedSetting(int owningUserId) {
+ synchronized (mLock) {
+ final Setting setting = getGlobalSetting(
+ Global.LOCATION_GLOBAL_KILL_SWITCH);
+ if (!"1".equals(setting.getValue())) {
+ return null;
+ }
+ // Global kill-switch is enabled. Return an empty value.
+ final SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
+ SETTINGS_TYPE_SECURE, owningUserId);
+ return settingsState.new Setting(
+ Secure.LOCATION_PROVIDERS_ALLOWED,
+ "", // value
+ "", // tag
+ "", // default value
+ "", // package name
+ false, // from system
+ "0" // id
+ ) {
+ @Override
+ public boolean update(String value, boolean setDefault, String packageName,
+ String tag, boolean forceNonSystemPackage) {
+ Slog.wtf(LOG_TAG, "update shoudln't be called on this instance.");
+ return false;
+ }
+ };
+ }
+ }
+
private boolean insertSecureSetting(String name, String value, String tag,
boolean makeDefault, int requestingUserId, boolean forceNotify) {
if (DEBUG) {
@@ -2780,6 +2803,12 @@
}
mHandler.obtainMessage(MyHandler.MSG_NOTIFY_DATA_CHANGED).sendToTarget();
+
+ // When the global kill switch is updated, send the change notification for
+ // the location setting.
+ if (isGlobalSettingsKey(key) && Global.LOCATION_GLOBAL_KILL_SWITCH.equals(name)) {
+ notifyLocationChangeForRunningUsers();
+ }
}
private void maybeNotifyProfiles(int type, int userId, Uri uri, String name,
@@ -2799,6 +2828,24 @@
}
}
+ private void notifyLocationChangeForRunningUsers() {
+ final List<UserInfo> users = mUserManager.getUsers(/*excludeDying=*/ true);
+
+ for (int i = 0; i < users.size(); i++) {
+ final int userId = users.get(i).id;
+
+ if (!mUserManager.isUserRunning(UserHandle.of(userId))) {
+ continue;
+ }
+
+ final int key = makeKey(SETTINGS_TYPE_GLOBAL, userId);
+ final Uri uri = getNotificationUriFor(key, Secure.LOCATION_PROVIDERS_ALLOWED);
+
+ mHandler.obtainMessage(MyHandler.MSG_NOTIFY_URI_CHANGED,
+ userId, 0, uri).sendToTarget();
+ }
+ }
+
private boolean isGlobalSettingsKey(int key) {
return getTypeFromKey(key) == SETTINGS_TYPE_GLOBAL;
}
@@ -2885,7 +2932,7 @@
} catch (SecurityException e) {
Slog.w(LOG_TAG, "Failed to notify for " + userId + ": " + uri, e);
}
- if (DEBUG) {
+ if (DEBUG || true) {
Slog.v(LOG_TAG, "Notifying for " + userId + ": " + uri);
}
} break;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index f901bca..a8a67ab 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -33,6 +33,7 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
+import android.provider.Settings.Global;
import android.providers.settings.GlobalSettingsProto;
import android.providers.settings.SettingsOperationProto;
import android.text.TextUtils;
@@ -46,6 +47,7 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import libcore.io.IoUtils;
@@ -195,6 +197,51 @@
@GuardedBy("mLock")
private int mNextHistoricalOpIdx;
+ public static final int SETTINGS_TYPE_GLOBAL = 0;
+ public static final int SETTINGS_TYPE_SYSTEM = 1;
+ public static final int SETTINGS_TYPE_SECURE = 2;
+ public static final int SETTINGS_TYPE_SSAID = 3;
+
+ public static final int SETTINGS_TYPE_MASK = 0xF0000000;
+ public static final int SETTINGS_TYPE_SHIFT = 28;
+
+ public static int makeKey(int type, int userId) {
+ return (type << SETTINGS_TYPE_SHIFT) | userId;
+ }
+
+ public static int getTypeFromKey(int key) {
+ return key >>> SETTINGS_TYPE_SHIFT;
+ }
+
+ public static int getUserIdFromKey(int key) {
+ return key & ~SETTINGS_TYPE_MASK;
+ }
+
+ public static String settingTypeToString(int type) {
+ switch (type) {
+ case SETTINGS_TYPE_GLOBAL: {
+ return "SETTINGS_GLOBAL";
+ }
+ case SETTINGS_TYPE_SECURE: {
+ return "SETTINGS_SECURE";
+ }
+ case SETTINGS_TYPE_SYSTEM: {
+ return "SETTINGS_SYSTEM";
+ }
+ case SETTINGS_TYPE_SSAID: {
+ return "SETTINGS_SSAID";
+ }
+ default: {
+ return "UNKNOWN";
+ }
+ }
+ }
+
+ public static String keyToString(int key) {
+ return "Key[user=" + getUserIdFromKey(key) + ";type="
+ + settingTypeToString(getTypeFromKey(key)) + "]";
+ }
+
public SettingsState(Context context, Object lock, File file, int key,
int maxBytesPerAppPackage, Looper looper) {
// It is important that we use the same lock as the settings provider
@@ -604,6 +651,13 @@
for (int i = 0; i < settingCount; i++) {
Setting setting = settings.valueAt(i);
+ if (setting.isTransient()) {
+ if (DEBUG_PERSISTENCE) {
+ Slog.i(LOG_TAG, "[SKIPPED PERSISTING]" + setting.getName());
+ }
+ continue;
+ }
+
writeSingleSetting(mVersion, serializer, setting.getId(), setting.getName(),
setting.getValue(), setting.getDefaultValue(), setting.getPackageName(),
setting.getTag(), setting.isDefaultFromSystem());
@@ -914,6 +968,14 @@
return update(this.defaultValue, false, packageName, null, true);
}
+ public boolean isTransient() {
+ switch (getTypeFromKey(getKey())) {
+ case SETTINGS_TYPE_GLOBAL:
+ return ArrayUtils.contains(Global.TRANSIENT_SETTINGS, getName());
+ }
+ return false;
+ }
+
public boolean update(String value, boolean setDefault, String packageName, String tag,
boolean forceNonSystemPackage) {
if (NULL_VALUE.equals(value)) {
diff --git a/packages/SettingsProvider/test/Android.mk b/packages/SettingsProvider/test/Android.mk
index a9707d4..902f1c7 100644
--- a/packages/SettingsProvider/test/Android.mk
+++ b/packages/SettingsProvider/test/Android.mk
@@ -12,7 +12,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
-LOCAL_JAVA_LIBRARIES := legacy-android-test
+LOCAL_JAVA_LIBRARIES := android.test.base
LOCAL_PACKAGE_NAME := SettingsProviderTest
diff --git a/packages/Shell/res/values-fa/strings.xml b/packages/Shell/res/values-fa/strings.xml
index 75e7760..d4bb3c6 100644
--- a/packages/Shell/res/values-fa/strings.xml
+++ b/packages/Shell/res/values-fa/strings.xml
@@ -23,8 +23,8 @@
<string name="bugreport_updating_title" msgid="4423539949559634214">"اضافه کردن جزئیات به گزارش اشکال"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"لطفاً منتظر بمانید..."</string>
<string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"گزارش مشکل بهزودی در تلفن نشان داده میشود"</string>
- <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"برای به اشتراک گذاشتن گزارش اشکالتان، انتخاب کنید"</string>
- <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"برای به اشتراک گذاشتن گزارش اشکال، ضربه بزنید"</string>
+ <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"برای همرسانی گزارش اشکالتان، انتخاب کنید"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"برای همرسانی گزارش اشکال، ضربه بزنید"</string>
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"انتخاب کنید تا گزارش اشکالتان بدون عکس صفحهنمایش به اشتراک گذاشته شود یا منتظر بمانید گرفتن عکس از صفحهنمایش تمام شود"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"برای اشتراکگذاری گزارش مشکل بدون عکس صفحهنمایش، ضربه بزنید یا صبر کنید تا عکس صفحهنمایش گرفته شود."</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"برای اشتراکگذاری گزارش مشکل بدون عکس صفحهنمایش، ضربه بزنید یا صبر کنید تا عکس صفحهنمایش گرفته شود."</string>
diff --git a/packages/Shell/src/com/android/shell/Screenshooter.java b/packages/Shell/src/com/android/shell/Screenshooter.java
index 8e27edf..8e01619 100644
--- a/packages/Shell/src/com/android/shell/Screenshooter.java
+++ b/packages/Shell/src/com/android/shell/Screenshooter.java
@@ -17,12 +17,11 @@
package com.android.shell;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.Point;
+import android.graphics.Rect;
import android.hardware.display.DisplayManagerGlobal;
import android.util.Log;
import android.view.Display;
-import android.view.Surface;
import android.view.SurfaceControl;
/**
@@ -35,18 +34,6 @@
private static final String TAG = "Screenshooter";
- /** Rotation constant: Freeze rotation to 0 degrees (natural orientation) */
- public static final int ROTATION_FREEZE_0 = Surface.ROTATION_0;
-
- /** Rotation constant: Freeze rotation to 90 degrees . */
- public static final int ROTATION_FREEZE_90 = Surface.ROTATION_90;
-
- /** Rotation constant: Freeze rotation to 180 degrees . */
- public static final int ROTATION_FREEZE_180 = Surface.ROTATION_180;
-
- /** Rotation constant: Freeze rotation to 270 degrees . */
- public static final int ROTATION_FREEZE_270 = Surface.ROTATION_270;
-
/**
* Takes a screenshot.
*
@@ -60,78 +47,21 @@
final int displayWidth = displaySize.x;
final int displayHeight = displaySize.y;
- final float screenshotWidth;
- final float screenshotHeight;
-
- final int rotation = display.getRotation();
- switch (rotation) {
- case ROTATION_FREEZE_0: {
- screenshotWidth = displayWidth;
- screenshotHeight = displayHeight;
- } break;
- case ROTATION_FREEZE_90: {
- screenshotWidth = displayHeight;
- screenshotHeight = displayWidth;
- } break;
- case ROTATION_FREEZE_180: {
- screenshotWidth = displayWidth;
- screenshotHeight = displayHeight;
- } break;
- case ROTATION_FREEZE_270: {
- screenshotWidth = displayHeight;
- screenshotHeight = displayWidth;
- } break;
- default: {
- throw new IllegalArgumentException("Invalid rotation: "
- + rotation);
- }
- }
-
+ int rotation = display.getRotation();
+ Rect crop = new Rect(0, 0, displayWidth, displayHeight);
Log.d(TAG, "Taking screenshot of dimensions " + displayWidth + " x " + displayHeight);
// Take the screenshot
Bitmap screenShot =
- SurfaceControl.screenshot((int) screenshotWidth, (int) screenshotHeight);
+ SurfaceControl.screenshot(crop, displayWidth, displayHeight, rotation);
if (screenShot == null) {
- Log.e(TAG, "Failed to take screenshot of dimensions " + screenshotWidth + " x "
- + screenshotHeight);
+ Log.e(TAG, "Failed to take screenshot of dimensions " + displayWidth + " x "
+ + displayHeight);
return null;
}
- // Rotate the screenshot to the current orientation
- if (rotation != ROTATION_FREEZE_0) {
- Bitmap unrotatedScreenShot = Bitmap.createBitmap(displayWidth, displayHeight,
- Bitmap.Config.ARGB_8888, screenShot.hasAlpha(), screenShot.getColorSpace());
- Canvas canvas = new Canvas(unrotatedScreenShot);
- canvas.translate(unrotatedScreenShot.getWidth() / 2,
- unrotatedScreenShot.getHeight() / 2);
- canvas.rotate(getDegreesForRotation(rotation));
- canvas.translate(- screenshotWidth / 2, - screenshotHeight / 2);
- canvas.drawBitmap(screenShot, 0, 0, null);
- canvas.setBitmap(null);
- screenShot.recycle();
- screenShot = unrotatedScreenShot;
- }
-
// Optimization
screenShot.setHasAlpha(false);
return screenShot;
}
-
- private static float getDegreesForRotation(int value) {
- switch (value) {
- case Surface.ROTATION_90: {
- return 360f - 90f;
- }
- case Surface.ROTATION_180: {
- return 360f - 180f;
- }
- case Surface.ROTATION_270: {
- return 360f - 270f;
- } default: {
- return 0;
- }
- }
- }
-
}
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index 8cc2ce2..5b8881c 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -15,6 +15,7 @@
-keep class com.android.systemui.statusbar.tv.TvStatusBar
-keep class com.android.systemui.car.CarSystemUIFactory
-keep class com.android.systemui.SystemUIFactory
+-keep class * extends com.android.systemui.SystemUI
-keepclassmembers class ** {
public void onBusEvent(**);
diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml
index eac0455..c745fe8 100644
--- a/packages/SystemUI/res-keyguard/values-af/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-af/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Voer wagwoord in om te ontsluit"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Tik PIN in om te ontsluit"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Verkeerde PIN-kode."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Ongeldige kaart."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Gelaai"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Laai"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Laai tans vinnig"</string>
diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml
index 8fb0539..f4e3001 100644
--- a/packages/SystemUI/res-keyguard/values-am/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-am/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"ለመክፈት የይለፍ ቃል ይተይቡ"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"ለመክፈት ፒን ይተይቡ"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"ትክክል ያልሆነ ፒን ኮድ።"</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"ልክ ያልሆነ ካርድ።"</string>
<string name="keyguard_charged" msgid="2222329688813033109">"ባትሪ ሞልቷል"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"ኃይል በመሙላት ላይ"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"ኃይል በፍጥነት በመሙላት ላይ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml
index ab0e8ea..a868b7c 100644
--- a/packages/SystemUI/res-keyguard/values-az/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-az/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Kilidi açmaq üçün parol daxil edin"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Kilidi açmaq üçün PIN daxil edin"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Yanlış PIN kod."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Yanlış Kart."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Enerji yığdı"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Enerji yığır"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Sürətlə enerji yığır"</string>
diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml
index 8dbdd5c..c098396 100644
--- a/packages/SystemUI/res-keyguard/values-bg/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Въведете парола, за да отключите"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Въведете ПИН кода, за да отключите"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Неправилен ПИН код."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Картата е невалидна."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Заредена"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Зарежда се"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Зарежда се бързо"</string>
diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml
index 0665ac0..f5864cd 100644
--- a/packages/SystemUI/res-keyguard/values-cs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Zadejte heslo pro odemknutí"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Zadejte kód PIN pro odemknutí"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Nesprávný kód PIN."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Neplatná karta."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Nabito"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Nabíjení"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Rychlé nabíjení"</string>
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index 354aa96..cb9989f 100644
--- a/packages/SystemUI/res-keyguard/values-da/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-da/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Indtast adgangskoden for at låse op"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Indtast pinkoden for at låse op"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Forkert pinkode."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Ugyldigt kort."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Opladet"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Oplader"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Oplader hurtigt"</string>
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index 9a5ad0e..372ca16 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Bitte gib das Passwort zum Entsperren ein"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Bitte gib die PIN zum Entsperren ein"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Falscher PIN-Code."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Ungültige Karte."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Aufgeladen"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Wird aufgeladen"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Schnelles Aufladen"</string>
diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml
index 6ec3e57..48faeba 100644
--- a/packages/SystemUI/res-keyguard/values-el/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-el/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Πληκτρολογήστε τον κωδικό πρόσβασης για ξεκλείδωμα"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Πληκτρολογήστε τον αριθμό PIN για ξεκλείδωμα"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Λανθασμένος κωδικός PIN."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Μη έγκυρη κάρτα."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Φορτίστηκε"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Φόρτιση σε εξέλιξη"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Ταχεία φόρτιση"</string>
diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
index 0c5989b..b7c026f 100644
--- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Ingresa la contraseña para desbloquearlo"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Ingresa el PIN para desbloquearlo"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Código PIN incorrecto"</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Tarjeta no válida"</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Cargada"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Cargando"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Carga rápida"</string>
diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml
index 4c3cf6f..b2c00bf 100644
--- a/packages/SystemUI/res-keyguard/values-et/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-et/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Avamiseks sisestage parool"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Avamiseks sisestage PIN-kood"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Vale PIN-kood."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Kehtetu kaart."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Laetud"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Laadimine"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Kiiresti laadimine"</string>
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index f7f3d58..c8eab84 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Idatzi desblokeatzeko pasahitza"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Idatzi desblokeatzeko PIN kodea"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN kode hori ez da zuzena."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Txartelak ez du balio."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Kargatuta"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Kargatzen"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Bizkor kargatzen"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml
index 43f8197..819b0e8 100644
--- a/packages/SystemUI/res-keyguard/values-fa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"برای بازکردن قفل، گذرواژه را وارد کنید"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"برای بازکردن قفل، پین را تایپ کنید"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"کد پین اشتباه است."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"کارت نامعتبر"</string>
<string name="keyguard_charged" msgid="2222329688813033109">"شارژ کامل شد"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"درحال شارژ شدن"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"شارژ سریع"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index 1e7548e1..b3ed4c5 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Saisissez le mot de passe pour déverrouiller le clavier"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Saisissez le code pour déverrouiller le clavier"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Le code est incorrect."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Carte non valide."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Chargé"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"En charge…"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Chargement rapide…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index 62ed064..40966c0 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -134,5 +134,5 @@
<item quantity="one">डिवाइस को <xliff:g id="NUMBER_1">%d</xliff:g> घंटों से अनलॉक नहीं किया गया है. पासवर्ड की पुष्टि करें.</item>
<item quantity="other">डिवाइस को <xliff:g id="NUMBER_1">%d</xliff:g> घंटों से अनलॉक नहीं किया गया है. पासवर्ड की पुष्टि करें.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"अंगुली की पहचान नहीं हो सकी"</string>
+ <string name="fingerprint_not_recognized" msgid="348813995267914625">"उंगली की पहचान नहीं हो सकी"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml
index 34c3a5a..4247ede 100644
--- a/packages/SystemUI/res-keyguard/values-hr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Unesite zaporku da biste otključali"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Unesite PIN da biste otključali"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN kôd nije točan."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Nevažeća kartica."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Napunjeno"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Punjenje"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Brzo punjenje"</string>
diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml
index a1922ee..30ccb67 100644
--- a/packages/SystemUI/res-keyguard/values-hu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"A feloldáshoz írja be a jelszót"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"A feloldáshoz írja be a PIN-kódot"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Helytelen PIN-kód."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Érvénytelen kártya."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Feltöltve"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Töltés folyamatban"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Gyors töltés folyamatban"</string>
diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml
index 191c66e..6d92dba 100644
--- a/packages/SystemUI/res-keyguard/values-is/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-is/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Sláðu inn aðgangsorðið til að opna"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Sláðu inn PIN-númer til að opna"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Rangt PIN-númer."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Ógilt kort."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Fullhlaðin"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Í hleðslu"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Hröð hleðsla"</string>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index 9ea32df..f449202 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Inserisci password per sbloccare"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Inserisci PIN per sbloccare"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Codice PIN errato."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Scheda non valida."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Carico"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"In carica"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Ricarica veloce"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml
index 4b5be4f..8aa2e47 100644
--- a/packages/SystemUI/res-keyguard/values-ja/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"ロックを解除するにはパスワードを入力してください"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"ロックを解除するには PIN を入力してください"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN コードが無効です。"</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"無効なカードです。"</string>
<string name="keyguard_charged" msgid="2222329688813033109">"充電が完了しました"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"充電しています"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"急速充電しています"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml
index 5da8122..1ff7a96 100644
--- a/packages/SystemUI/res-keyguard/values-ka/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"განსაბლოკად აკრიფეთ პაროლი"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"განსაბლოკად აკრიფეთ PIN-კოდი"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN-კოდი არასწორია."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"ბარათი არასწორია."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"დატენილია"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"მიმდინარეობს დატენა"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"მიმდინარეობს სწრაფი დატენა"</string>
diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index a99f2ec..4b0a7ff 100644
--- a/packages/SystemUI/res-keyguard/values-kk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Құлпын ашу үшін құпия сөзді теріңіз"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Құлпын ашу үшін PIN кодын енгізіңіз"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN коды қате"</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Жарамсыз карта."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Зарядталды"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Зарядталуда"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Жылдам зарядталуда"</string>
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index 7241ac3..6a48197 100644
--- a/packages/SystemUI/res-keyguard/values-km/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-km/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"វាយបញ្ចូលពាក្យសម្ងាត់ ដើម្បីដោះសោ"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"វាយបញ្ចូលកូដ PIN ដើម្បីដោះសោ"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"កូដ PIN មិនត្រឹមត្រូវទេ។"</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"បណ្ណមិនត្រឹមត្រូវទេ។"</string>
<string name="keyguard_charged" msgid="2222329688813033109">"បានសាកថ្ម"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"កំពុងសាកថ្ម"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"សាកយ៉ាងឆាប់រហ័ស"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml
index ff27639..d4054e8 100644
--- a/packages/SystemUI/res-keyguard/values-ky/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Кулпуну ачуу үчүн сырсөздү териңиз"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Кулпуну ачуу үчүн PIN-кодду териңиз"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN-код туура эмес."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"SIM-карта жараксыз."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Кубатталды"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Кубатталууда"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Ыкчам кубатталууда"</string>
diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml
index 11823a3..e72349b 100644
--- a/packages/SystemUI/res-keyguard/values-lo/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml
@@ -29,6 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"ພິມລະຫັດເພື່ອປົດລັອກ"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"ພິມລະຫັດ PIN ເພື່ອປົດລັອກ"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"ລະຫັດ PIN ບໍ່ຖືກຕ້ອງ."</string>
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"ບັດບໍ່ຖືກຕ້ອງ."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"ສາກເຕັມແລ້ວ."</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"ກຳລັງສາກໄຟ"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"ກຳລັງສາກດ່ວນ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml
index 9e59fb1..0f51f00 100644
--- a/packages/SystemUI/res-keyguard/values-lt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Įveskite slaptažodį, kad atrakintumėte"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Įveskite PIN kodą, kad atrakintumėte"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Netinkamas PIN kodas."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Netinkama kortelė."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Įkrauta"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Įkraunama"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Greitai įkraunama"</string>
diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml
index 3447973..bdd5dd5 100644
--- a/packages/SystemUI/res-keyguard/values-lv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Ievadiet paroli, lai atbloķētu."</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Ievadiet PIN kodu, lai atbloķētu."</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN kods nav pareizs."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Nederīga karte."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Akumulators uzlādēts"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Notiek uzlāde"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Notiek ātrā uzlāde"</string>
diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml
index 263b3c9..e14989f 100644
--- a/packages/SystemUI/res-keyguard/values-mk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Напишете ја лозинката за да отклучите"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Напишете PIN-код за да отклучите"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Погрешен PIN-код."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Неважечка картичка."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Полна"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Се полни"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Брзо полнење"</string>
diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml
index 44c186f..c8d0b2d 100644
--- a/packages/SystemUI/res-keyguard/values-mn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Түгжээг тайлахын тулд нууц үгийг оруулна уу"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Түгжээг тайлахын тулд ПИН кодыг оруулна уу"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"ПИН код буруу байна."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Карт хүчингүй байна."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Цэнэглэсэн"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Цэнэглэж байна"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Хурдан цэнэглэж байна"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml
index efffa8c..6b8c1e9 100644
--- a/packages/SystemUI/res-keyguard/values-ms/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Taip kata laluan untuk membuka kunci"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Taip PIN untuk membuka kunci"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Kod PIN salah."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Kad Tidak Sah."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Sudah dicas"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Mengecas"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Mengecas dengan cepat"</string>
diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml
index 7b598e1..46e8c2e 100644
--- a/packages/SystemUI/res-keyguard/values-my/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-my/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"လော့ခ်ဖွင့်ရန် စကားဝှက်ကို ထည့်ပါ"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"လော့ခ်ဖွင့်ရန် ပင်နံပါတ်ထည့်ပါ"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"ပင်နံပါတ် မှားနေသည်။"</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"ကဒ် မမှန်ကန်ပါ။"</string>
<string name="keyguard_charged" msgid="2222329688813033109">"အားသွင်းပြီးပါပြီ"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"အားသွင်းနေပါသည်"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"လျှင်မြန်စွာ အားသွင်းနေသည်"</string>
diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml
index 1fef576..b206395 100644
--- a/packages/SystemUI/res-keyguard/values-nb/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Skriv inn passordet for å låse opp"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Skriv inn PIN-koden for å låse opp"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Feil PIN-kode."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Ugyldig kort."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Oppladet"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Lader"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Lader raskt"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index 4f6fcb9..70d13e6 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -59,8 +59,8 @@
<string name="kg_wrong_password" msgid="4580683060277329277">"Palavra-passe incorreta"</string>
<string name="kg_wrong_pin" msgid="4785660766909463466">"PIN incorreto"</string>
<plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="4368805541257003755">
- <item quantity="one">Tente novamente dentro de 1 segundo.</item>
<item quantity="other">Tente novamente dentro de <xliff:g id="NUMBER">%d</xliff:g> segundos.</item>
+ <item quantity="one">Tente novamente dentro de 1 segundo.</item>
</plurals>
<string name="kg_pattern_instructions" msgid="5547646893001491340">"Desenhe o seu padrão"</string>
<string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Introduza o PIN do cartão SIM."</string>
@@ -97,13 +97,13 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="8364140853305528449">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="3389829202093674267">"Código PIN do cartão SIM incorreto. Tem de contactar o seu operador para desbloquear o dispositivo."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="4314341367727055967">
- <item quantity="one">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de precisar de contactar o seu operador para desbloquear o dispositivo.</item>
<item quantity="other">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas.</item>
+ <item quantity="one">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de precisar de contactar o seu operador para desbloquear o dispositivo.</item>
</plurals>
<string name="kg_password_wrong_puk_code_dead" msgid="3329017604125179374">"Cartão SIM inutilizável. Contacte o seu operador."</string>
<plurals name="kg_password_wrong_puk_code" formatted="false" msgid="2287504898931957513">
- <item quantity="one">Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável.</item>
<item quantity="other">Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar permanentemente inutilizável.</item>
+ <item quantity="one">Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável.</item>
</plurals>
<string name="kg_password_pin_failed" msgid="8769990811451236223">"Falha ao introduzir o PIN do cartão SIM!"</string>
<string name="kg_password_puk_failed" msgid="1331621440873439974">"Falha ao introduzir o PUK do cartão SIM!"</string>
@@ -123,16 +123,16 @@
<string name="kg_prompt_reason_device_admin" msgid="3452168247888906179">"Dispositivo bloqueado pelo gestor"</string>
<string name="kg_prompt_reason_user_request" msgid="8236951765212462286">"O dispositivo foi bloqueado manualmente"</string>
<plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="71299470072448533">
- <item quantity="one">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirme o padrão.</item>
<item quantity="other">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirme o padrão.</item>
+ <item quantity="one">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirme o padrão.</item>
</plurals>
<plurals name="kg_prompt_reason_time_pin" formatted="false" msgid="34586942088144385">
- <item quantity="one">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirme o PIN.</item>
<item quantity="other">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirme o PIN.</item>
+ <item quantity="one">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirme o PIN.</item>
</plurals>
<plurals name="kg_prompt_reason_time_password" formatted="false" msgid="257297696215346527">
- <item quantity="one">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirme a palavra-passe.</item>
<item quantity="other">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirme a palavra-passe.</item>
+ <item quantity="one">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirme a palavra-passe.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Não reconhecido"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml
index 3f27010..f629957 100644
--- a/packages/SystemUI/res-keyguard/values-ru/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Введите пароль"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Введите PIN-код для разблокировки"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Неверный PIN-код."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Ошибка SIM-карты."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Батарея заряжена"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Зарядка батареи"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Быстрая зарядка"</string>
diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml
index e48d81d..4981855 100644
--- a/packages/SystemUI/res-keyguard/values-si/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-si/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"අගුළු ඇරීමට මුරපදය ටයිප් කරන්න"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"අගුළු හැරීමට PIN එක ටයිප් කරන්න"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"වැරදි PIN කේතයකි."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"වලංගු නොවන කාඩ්පත."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"අරෝපිතයි"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"ආරෝපණය වෙමින්"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"වේගයෙන් ආරෝපණය වෙමින්"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml
index 9f397e6..99007ee 100644
--- a/packages/SystemUI/res-keyguard/values-sk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Zadajte heslo na odomknutie"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Zadajte kód PIN na odomknutie"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Nesprávny kód PIN."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Neplatná karta."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Nabité"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Nabíja sa"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Rýchle nabíjanie"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml
index 9004a1e..2a08765 100644
--- a/packages/SystemUI/res-keyguard/values-sl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Vnesite geslo za odklepanje"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Vnesite kodo PIN za odklepanje"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Napačna koda PIN."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Neveljavna kartica"</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Akumulator napolnjen"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Polnjenje"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Hitro polnjenje"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml
index 2521b99..fd52d39 100644
--- a/packages/SystemUI/res-keyguard/values-sq/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Shkruaj fjalëkalimin për të shkyçur"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Shkruaj kodin PIN për ta shkyçur"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Kodi PIN është i pasaktë."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Karta e pavlefshme."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"I ngarkuar"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Po ngarkon"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Po ngarkon me shpejtësi"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index 03f2086..dc41e0d 100644
--- a/packages/SystemUI/res-keyguard/values-sv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Lås upp med lösenordet"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Lås upp med pinkoden"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Fel pinkod."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Ogiltigt kort."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Laddat"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Laddas"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Laddas snabbt"</string>
diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml
index 46d6ba8..d802f01 100644
--- a/packages/SystemUI/res-keyguard/values-th/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-th/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"พิมพ์รหัสผ่านเพื่อปลดล็อก"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"พิมพ์ PIN เพื่อปลดล็อก"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"รหัส PIN ไม่ถูกต้อง"</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"การ์ดไม่ถูกต้อง"</string>
<string name="keyguard_charged" msgid="2222329688813033109">"ชาร์จแล้ว"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"กำลังชาร์จ"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"กำลังชาร์จเร็ว"</string>
diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml
index 2998904..7e84d2f 100644
--- a/packages/SystemUI/res-keyguard/values-tl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tl/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"I-type ang password upang i-unlock"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"I-type ang PIN upang i-unlock"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Mali ang PIN code."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Di-wasto ang Card."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Tapos nang mag-charge"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Nagcha-charge"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Mabilis na nagcha-charge"</string>
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index 43d01b5..f25928a 100644
--- a/packages/SystemUI/res-keyguard/values-uk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Введіть пароль, щоб розблокувати"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Введіть PIN-код, щоб розблокувати"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Неправильний PIN-код."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Недійсна картка."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Заряджено"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Заряджається"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Швидке заряджання"</string>
diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml
index 6b32d3a..67af2bf 100644
--- a/packages/SystemUI/res-keyguard/values-vi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Nhập mật khẩu để mở khóa"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Nhập mã PIN để mở khóa"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Mã PIN không chính xác."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Thẻ không hợp lệ."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Đã sạc đầy"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Đang sạc"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Đang sạc nhanh"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
index 1c159ca..f343141 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"輸入密碼即可解鎖"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"輸入 PIN 碼即可解鎖"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN 碼不正確。"</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"SIM 卡無效。"</string>
<string name="keyguard_charged" msgid="2222329688813033109">"已完成充電"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"正在充電"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"正在快速充電"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index a1d072a..9e0165a 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"輸入密碼即可解鎖"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"輸入 PIN 碼即可解鎖"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN 碼不正確。"</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"卡片無效。"</string>
<string name="keyguard_charged" msgid="2222329688813033109">"充電完成"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"充電中"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"快速充電中"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml
index 4602237..2f456bd 100644
--- a/packages/SystemUI/res-keyguard/values-zu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Bhala iphasiwedi ukuze kuvuleke"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Faka i-PIN ukuvula"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Ikhodi ye-PIN engalungile!"</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Ikhadi elingavumelekile."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Kushajiwe"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Iyashaja"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Ishaja ngokushesha"</string>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 3dd0e6c..3a41681 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -367,4 +367,20 @@
<!-- Fingerprint hint message when finger was not recognized.-->
<string name="fingerprint_not_recognized">Not recognized</string>
+ <!-- Instructions telling the user remaining times when enter SIM PIN view. -->
+ <plurals name="kg_password_default_pin_message">
+ <item quantity="one">Enter SIM PIN, you have <xliff:g id="number">%d</xliff:g> remaining
+attempt before you must contact your carrier to unlock your device.</item>
+ <item quantity="other">Enter SIM PIN, you have <xliff:g id="number">%d</xliff:g> remaining
+attempts.</item>
+ </plurals>
+
+ <!-- Instructions telling the user remaining times when enter SIM PUK view. -->
+ <plurals name="kg_password_default_puk_message">
+ <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="
+number">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact carrier for details.</item>
+ <item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="
+number">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact carrier for details.</item>
+ </plurals>
+
</resources>
diff --git a/packages/SystemUI/res/drawable/ic_account_circle.xml b/packages/SystemUI/res/drawable/ic_account_circle.xml
new file mode 100644
index 0000000..3c5f01b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_account_circle.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48.0dp"
+ android:height="48.0dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:pathData="M24,0C10.8,0 0,10.8 0,24s10.8,24 24,24s24,-10.8 24,-24S37.200001,0 24,0zM24,7.2c3.96,0 7.2,3.24 7.2,7.2s-3.24,7.2 -7.2,7.2s-7.2,-3.24 -7.2,-7.2S20.040001,7.2 24,7.2zM24,41.279999c-6,0 -11.28,-3.12 -14.4,-7.68c0.12,-4.8 9.6,-7.44 14.4,-7.44s14.28,2.64 14.4,7.44C35.279999,38.16 30,41.279999 24,41.279999z"
+ android:fillColor="?attr/wallpaperTextColor"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/instant_icon.xml b/packages/SystemUI/res/drawable/instant_icon.xml
index 0039c81..8554daa 100644
--- a/packages/SystemUI/res/drawable/instant_icon.xml
+++ b/packages/SystemUI/res/drawable/instant_icon.xml
@@ -14,17 +14,13 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="40dp"
- android:height="40dp"
- android:viewportWidth="2.2"
- android:viewportHeight="2.2">
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportHeight="48"
+ android:viewportWidth="48">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M.1,1.1
- c0,.55 .45,1 1,1
- c.55,0 1,-.45 1,-1
- c0,-.55 -.45,-1 -1,-1
- c-.55,0 -1,.45 -1,1z
- M1.15,.95 l.5,0 l-.7,1 l0.1,-.7 l-.5,0 l.7,-1 z"/>
-</vector>
+ android:pathData="M35.8,18.9l-9.8,0.1l0.2,-19l-14.1,29.3l9.9,0l0,18.7z" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 6df1657..2e35d86 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -126,6 +126,7 @@
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="end"
+ android:layout_marginEnd="@*android:dimen/notification_content_margin_end"
android:layout_marginBottom="8dp" >
<TextView
android:id="@+id/more_settings"
@@ -139,7 +140,6 @@
android:text="@string/notification_done"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_marginEnd="8dp"
style="@style/TextAppearance.NotificationInfo.Button"/>
</LinearLayout>
</com.android.systemui.statusbar.NotificationInfo>
diff --git a/packages/SystemUI/res/layout/notification_snooze.xml b/packages/SystemUI/res/layout/notification_snooze.xml
index 3209f27..7476abd 100644
--- a/packages/SystemUI/res/layout/notification_snooze.xml
+++ b/packages/SystemUI/res/layout/notification_snooze.xml
@@ -35,7 +35,7 @@
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
- android:paddingStart="16dp"
+ android:paddingStart="@*android:dimen/notification_content_margin_start"
android:textColor="#DD000000"
android:paddingEnd="4dp"/>
@@ -53,7 +53,7 @@
style="@style/TextAppearance.NotificationInfo.Button"
android:layout_width="wrap_content"
android:layout_height="36dp"
- android:layout_marginEnd="8dp"
+ android:layout_marginEnd="@*android:dimen/notification_content_margin_end"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:text="@string/snooze_undo" />
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index fac254a..f563794 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.systemui.HardwareUiLayout
+<com.android.systemui.volume.VolumeUiLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -21,18 +21,19 @@
android:clipChildren="false" >
<RelativeLayout
android:id="@+id/volume_dialog"
- android:layout_width="@dimen/volume_dialog_panel_width"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical|end"
android:paddingTop="@dimen/volume_row_padding_bottom"
- android:layout_margin="12dp"
- android:background="?android:attr/actionBarItemBackground"
- android:translationZ="8dp" >
+ android:background="@drawable/rounded_full_bg_bottom"
+ android:translationZ="8dp"
+ android:clipChildren="false" >
<LinearLayout
android:id="@+id/volume_dialog_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false"
android:orientation="vertical" >
<LinearLayout
@@ -42,7 +43,55 @@
android:orientation="vertical" >
<!-- volume rows added and removed here! :-) -->
</LinearLayout>
- </LinearLayout>
+ <!-- special row for ringer mode -->
+ <RelativeLayout
+ android:id="@+id/ringer_mode"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/rounded_bg_full"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:layout_margin="10dp">
+
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/ringer_icon"
+ style="@style/VolumeButtons"
+ android:background="?android:selectableItemBackgroundBorderless"
+ android:layout_width="@dimen/volume_button_size"
+ android:layout_height="@dimen/volume_button_size"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:soundEffectsEnabled="false" />
+
+ <TextView
+ android:id="@+id/ringer_title"
+ android:text="@string/stream_ring"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:layout_toEndOf="@+id/ringer_icon"
+ android:layout_marginStart="64dp"
+ android:textColor="?android:attr/colorControlNormal"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:paddingStart="@dimen/volume_row_header_padding_start" />
+
+ <TextView
+ android:id="@+id/ringer_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:layout_alignParentEnd="true"
+ android:layout_centerVertical="true"
+ android:layout_marginEnd="14dp"
+ android:maxLines="1"
+ android:textColor="?android:attr/colorControlNormal"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
+ </RelativeLayout>
+ </LinearLayout>
</RelativeLayout>
-</com.android.systemui.HardwareUiLayout>
+</com.android.systemui.volume.VolumeUiLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/config.xml b/packages/SystemUI/res/values-af/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-af/config.xml
+++ b/packages/SystemUI/res/values-af/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index b8c4029..e527089 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Kennisgewings"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Battery is amper pap"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> oor"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> oor. Batterybespaarder is aan."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> oor. Batterybespaarder is aan."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-laaiery nie ondersteun nie.\nGebruik net die laaier wat verskaf is."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Laai met USB word nie gesteun nie."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Gebruik slegs die laaier wat verskaf is."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Instellings"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Skakel batterybespaarder aan?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Skakel Batterybespaarder aan?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Skakel aan"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Skakel batterybespaarder aan"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Skakel Batterybespaarder aan"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Instellings"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Outodraai skerm"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth-verbind"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Stel invoer metodes op"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fisiese sleutelbord"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Laat die program <xliff:g id="APPLICATION">%1$s</xliff:g> toe om toegang tot die USB-toestel te kry?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Laat die program <xliff:g id="APPLICATION">%1$s</xliff:g> toe om toegang tot die USB-toebehoorsel te kry?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Maak <xliff:g id="ACTIVITY">%1$s</xliff:g> oop wanneer hierdie USB-toestel gekoppel is?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Maak <xliff:g id="ACTIVITY">%1$s</xliff:g> oop wanneer hierdie USB-toebehoorsel gekoppel is?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Gee <xliff:g id="APPLICATION">%1$s</xliff:g> toegang tot <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Gee <xliff:g id="APPLICATION">%1$s</xliff:g> toegang tot <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Maak <xliff:g id="APPLICATION">%1$s</xliff:g> oop om <xliff:g id="USB_DEVICE">%2$s</xliff:g> te hanteer?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Maak <xliff:g id="APPLICATION">%1$s</xliff:g> oop om <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> te hanteer?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Geen geïnstalleerde programme werk met hierdie USB-toebehoorsel nie. Vind meer uit oor hierdie toebehoorsel by <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB-toebehoorsel"</string>
<string name="label_view" msgid="6304565553218192990">"Sien"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Gebruik by verstek vir hierdie USB-toestel"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Gebruik by verstek vir hierdie USB-toebehoorsel"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Maak <xliff:g id="APPLICATION">%1$s</xliff:g> altyd oop wanneer <xliff:g id="USB_DEVICE">%2$s</xliff:g> gekoppel is"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Maak <xliff:g id="APPLICATION">%1$s</xliff:g> altyd oop wanneer <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> gekoppel is"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Laat USB-ontfouting toe?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Die rekenaar se RSA-sleutel-vingerafdruk is:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Laat altyd toe van hierdie rekenaar af"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is onderbreek"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Die datalimiet wat jy gestel het, is bereik. Jy gebruik nie meer mobiele data nie.\n\nAs jy voortgaan, kan heffings vir datagebruik geld."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervat"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding nie"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi gekoppel"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Soek vir GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Ligging deur GPS gestel"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Liggingversoeke aktief"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Verwyder gebruiker?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Alle programme en data van hierdie gebruiker sal uitgevee word."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Verwyder"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Batterybespaarder is aan"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Batterybespaarder is aan"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Verminder werkverrigting en agtergronddata"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Skakel batterybespaarder af"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Skakel Batterybespaarder af"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sal alles begin vasvang wat op jou skerm gewys word."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Moenie weer wys nie"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Vee alles uit"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d minuut</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Batterygebruik"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Batterybespaarder is nie beskikbaar wanneer gelaai word nie"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Batterybespaarder"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterybespaarder is nie beskikbaar wanneer gelaai word nie"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Batterybespaarder"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Verminder werkverrigting en agtergronddata"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Knoppie <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-am/config.xml b/packages/SystemUI/res/values-am/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-am/config.xml
+++ b/packages/SystemUI/res/values-am/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 1ad6367..8ee77e1 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"ማሳወቂያዎች"</string>
<string name="battery_low_title" msgid="6456385927409742437">"የባትሪ ኃይል አነስተኛ ነው"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> ይቀራል"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> ይቀራል። የባትሪ መቆጠቢያ በርቷል።"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> ይቀራል። ባትሪ ቆጣቢ በርቷል።"</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB ኃይል መሙያ አይታገዝም።\n የቀረበውን ኃይል መሙያ ብቻ ተጠቀም።"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"የUSB ኃይል መሙላት አይደገፍም።"</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"የቀረበውን ኃይል መሙያ ብቻ ይጠቀሙ።"</string>
<string name="battery_low_why" msgid="4553600287639198111">"ቅንብሮች"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"ባትሪ ቆጣቢ ይብራ?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"ባትሪ ቆጣቢ ይብራ?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"አብራ"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"ባትሪ ቆጣቢን አብራ"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"ባትሪ ቆጣቢን አብራ"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ቅንብሮች"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"ማያ በራስ ሰር አሽከርክር"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"ብሉቱዝ አያይዝ"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"የግቤት ስልቶችን አዘጋጅ"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"የሚዳሰስ የቁልፍ ሰሌዳ"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"መተግበሪያ <xliff:g id="APPLICATION">%1$s</xliff:g> የUSB መሣሪያን ለመድረስ ይፍቀድ?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"መተግበሪያ <xliff:g id="APPLICATION">%1$s</xliff:g> የUSB ተቀጥላ ላይ እንዲደርስ ፍቀድ?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"የዚህ USB ተቀጥላ ሲያያዝ <xliff:g id="ACTIVITY">%1$s</xliff:g>ይከፈት?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"የዚህ USB ተቀጥላ ሲያያዝ <xliff:g id="ACTIVITY">%1$s</xliff:g> ይከፈት?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> <xliff:g id="USB_DEVICE">%2$s</xliff:g>ን እንዲደርስበት ይፈቀድለት?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>ን እንዲደርስበት ይፈቀድለት?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ን እንዲይዘው <xliff:g id="APPLICATION">%1$s</xliff:g> ይክፈት?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>ን እንዲይዘው <xliff:g id="APPLICATION">%1$s</xliff:g> ይክፈት?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ምንም የተጫኑ መተግበሪያዎች ከዚህ የUSB ተቀጥላ ጋር አይሰሩም። በ<xliff:g id="URL">%1$s</xliff:g> ስለዚህ ተቀጥላ የበለጠ ለመረዳት።"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"የUSB ተቀጥላ"</string>
<string name="label_view" msgid="6304565553218192990">"ዕይታ"</string>
- <string name="always_use_device" msgid="1450287437017315906">"ለእዚህ USB መሣሪያ በነባሪነት ተጠቀም"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"ለእዚህ USB ተቀጥላ በነባሪነት ተጠቀም"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ሲገናኝ ሁልጊዜ <xliff:g id="APPLICATION">%1$s</xliff:g>ን ይክፈቱ"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ሲገናኝ ሁልጊዜ <xliff:g id="APPLICATION">%1$s</xliff:g>ን ይክፈቱ"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"የUSB ማረሚያ ይፈቀድ?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"የኮምፒውተሩ RSA ቁልፍ ጣት አሻራ ይሄ ነው፦\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"ሁልጊዜ ከዚህ ኮምፒውተር ፍቀድ"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ውሂብ ላፍታ ቆሟል"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"የውሂብ ገደቡ ላይ ተደርሷል። ከእንግዲህ የተንቀሳቃሽ ስልክ ውሂብ እየተጠቀሙ አይደሉም።\n\nከቆመበት ከቀጠሉ የውሂብ አጠቃቀም ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ።"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ከቆመበት ቀጥል"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ምንም በይነመረብ ተያያዥ የለም።"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ተያይዟል"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"ለGPS በመፈለግ ላይ"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"በ GPS የተዘጋጀ ሥፍራ"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"የአካባቢ ጥያቄዎች ነቅተዋል"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"ተጠቃሚ ይወገድ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"ሁሉም የዚህ ተጠቃሚ መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"አስወግድ"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"የባትሪ ኃይል ቆጣቢ በርቷል"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"ባትሪ ቆጣቢ በርቷል"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"አፈጻጸምን እና የጀርባ ውሂብ ይቀንሳል"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ባትሪ ቆጣቢን አጥፋ"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"ባትሪ ቆጣቢን አጥፋ"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> በማያ ገጽዎ ላይ የታየውን ነገር በሙሉ ማንሳት ይጀምራል።"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"ዳግመኛ አታሳይ"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"ሁሉንም አጽዳ"</string>
@@ -582,8 +580,8 @@
<item quantity="other"> %d ደቂቃዎች</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"የባትሪ አጠቃቀም"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"ኃይል በሚሞላበት ጊዜ ባትሪ ቆጣቢ አይገኝም"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"የባትሪ ኃይል ቆጣቢ"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ኃይል በሚሞላበት ጊዜ ባትሪ ቆጣቢ አይገኝም"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"ባትሪ ቆጣቢ"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"አፈጻጸምን እና የጀርባ ውሂብን ይቀንሳል"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"አዝራር <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"መነሻ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index d642118..48e8739 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -38,14 +38,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"الإشعارات"</string>
<string name="battery_low_title" msgid="6456385927409742437">"البطارية منخفضة"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"متبقي <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"متبقي <xliff:g id="PERCENTAGE">%s</xliff:g>. وضع توفير الطاقة قيد التشغيل."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"يتبقى <xliff:g id="PERCENTAGE">%s</xliff:g>. تم تفعيل ميزة توفير شحن البطارية."</string>
<string name="invalid_charger" msgid="4549105996740522523">"شحن USB غير معتمد.\nاستخدم الشاحن الموفر فقط."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"لا يمكن إجراء الشحن عبر USB."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"لا تستخدم سوى الشاحن المزوّد."</string>
<string name="battery_low_why" msgid="4553600287639198111">"الإعدادات"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"هل تريد تشغيل توفير شحن البطارية؟"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"هل تريد تفعيل ميزة توفير شحن البطارية؟"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"تشغيل"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"تشغيل توفير شحن البطارية"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"هل تريد تفعيل ميزة توفير شحن البطارية؟"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"الإعدادات"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"التدوير التلقائي للشاشة"</string>
@@ -247,8 +247,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"تم إيقاف البيانات مؤقتًا"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"تم الوصول إلى حد البيانات الذي عيَّنته. لم يُعد بإمكانك استخدام بيانات الجوال.\n\nفي حالة الاستئناف، قد يتم تطبيق الرسوم لاستخدام البيانات."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"استئناف"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"لا يوجد اتصال إنترنت"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi متصل"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"جارٍ البحث عن GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"تم تعيين الموقع بواسطة GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"طلبات الموقع نشطة"</string>
@@ -409,9 +407,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"هل تريد إزالة المستخدم؟"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"سيتم حذف جميع تطبيقات وبيانات هذا المستخدم."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"إزالة"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"وضع توفير الطاقة قيد التشغيل"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"تم تفعيل ميزة توفير شحن البطارية"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"لخفض مستوى الأداء وبيانات الخلفية"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"إيقاف توفير شحن البطارية"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"إيقاف ميزة توفير شحن البطارية"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> سيبدأ التقاط كل شيء يتم عرضه على الشاشة."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"عدم الإظهار مرة أخرى"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"محو الكل"</string>
@@ -606,8 +604,8 @@
<item quantity="one">دقيقة واحدة</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"استخدام البطارية"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"توفير شحن البطارية غير متاح أثناء الشحن"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"توفير شحن البطارية"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"وضع توفير شحن البطارية غير متاح أثناء الشحن."</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"توفير شحن البطارية"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"لخفض مستوى الأداء وبيانات الخلفية"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"الزر <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-az/config.xml b/packages/SystemUI/res/values-az/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-az/config.xml
+++ b/packages/SystemUI/res/values-az/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 82fc76a..de9ffe1 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Bildirişlər"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Enerji azdır"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> qalır"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> qalır. Enerjiyə qənaət aktivdir."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> qalır. Batareya Qənaəti aktivdir."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB ilə elektrik doldurma dəstəklənmir.\nYalnız adapter istifadə edin."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB qidalandırıcı dəstəklənmir."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Yalnız uyğun qidalandırıcı işlədin."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Ayarlar"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Enerjiyə qənaət aktivləşdirilsin?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Batareya Qənaəti aktiv edilsin?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Aktivləşdirin"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Enerjiyə qənaət rejimini aktivləşdirin"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Batareya Qənaətini aktiv edin"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ayarlar"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Ekran avtodönüşü"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tezerinq"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Daxiletmə metodlarını ayarlayın"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fiziki klaviatura"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə USB cihazına daxil olmağa icazə verilsin?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə USB aksesuarına qoşulmağa icazə verirsiniz?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"USB cihaz qoşulu olan zaman <xliff:g id="ACTIVITY">%1$s</xliff:g> açılsın mı?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"USB aksesuar qoşulu olan zaman <xliff:g id="ACTIVITY">%1$s</xliff:g> açılsın mı?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə <xliff:g id="USB_DEVICE">%2$s</xliff:g> cihazına giriş icazəsi verilsin?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> cihazına giriş icazəsi verilsin?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> cihazını idarə etmək üçün <xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqi açılsın?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> cihazını idarə etmək üçün <xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqi açılsın?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Heç bir quraşdırılmış tətbiq bu USB aksesuar ilə işləmir. Bu aksesuar haqqında daha ətraflı məlumatı <xliff:g id="URL">%1$s</xliff:g> adresindən öyrənin"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB aksesuar"</string>
<string name="label_view" msgid="6304565553218192990">"Göstər"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Bu USB cihaz üçün defolt olaraq istifadə edin."</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Bu USB aksesuar üçün defolt istifadə edin"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> qoşulduqda həmişə <xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqini açın"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> qoşulduqda həmişə <xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqini açın"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB sazlamaya icazə verilsin?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Kompüterin RSA barmaq izi: \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Bu kompüterdən həmişə icazə verilsin"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Məlumatlara fasilə verildi"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Ayarladığınız data limiti doldu. Artıq mobil datadan istifadə etmirsiniz.\n\nDavam etsəniz, data istifadəsi üçün ödəniş tutulacaq."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Davam et"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"İnternet bağlantısı yoxdur"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi qoşulub"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS Axtarışı"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Yer GPS tərəfindən müəyyən edildi"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Məkan sorğuları arxivi"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"İstifadəçi silinsin?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Bu istifadəçinin bütün tətbiqləri və datası silinəcək."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Silin"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Enerji qənaəti aktivdir"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Batareya Qənaəti aktivdir"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Performansı azaldır və arxa fon datasını məhdudlaşdırır"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Enerjiyə qənaət rejimini deaktiv edin"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Batareya Qənaətini deaktiv edin"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ekranınızda olan hər şeyin şəklini çəkəcək."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Daha göstərmə"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Hamısını silin"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d dəqiqə</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Batareya istifadəsi"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Batareya qənaəti doldurulma zamanı əlçatan deyil"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Batareya qənaəti"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Enerji Qənaəti doldurulma zamanı əlçatan deyil"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Enerji Qənaəti"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Performansı azaldır və arxa fon datasını məhdudlaşdırır"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Düymə <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Əsas səhifə"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/config.xml b/packages/SystemUI/res/values-b+sr+Latn/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/config.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index ce0c51f..4e38e5d 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -35,14 +35,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Obaveštenja"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Nivo napunjenosti baterije je nizak"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Još <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Još <xliff:g id="PERCENTAGE">%s</xliff:g>. Uključena je štednja baterije."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Još <xliff:g id="PERCENTAGE">%s</xliff:g>. Ušteda baterije je uključena."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Punjenje preko USB-a nije podržano.\nKoristite samo priloženi punjač."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Punjenje preko USB-a nije podržano."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Koristite samo punjač koji ste dobili."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Podešavanja"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Želite li da uključite štednju baterije?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Želite li da uključite Uštedu baterije?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Uključi"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Uključi štednju baterije"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Uključi Uštedu baterije"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Podešavanja"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatsko rotiranje ekrana"</string>
@@ -52,15 +52,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Veza preko Bluetooth-a"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Podesi metode unosa"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fizička tastatura"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Želite li da dozvolite aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> da pristupa USB uređaju?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Želite li da dozvolite aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> da pristupa USB pomoćnom uređaju?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Želite li da se otvori <xliff:g id="ACTIVITY">%1$s</xliff:g> kada se priključi ovaj USB uređaj?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Želite li da se otvori <xliff:g id="ACTIVITY">%1$s</xliff:g> kada se priključi ovaj USB dodatak?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Želite li da dozvolite da <xliff:g id="APPLICATION">%1$s</xliff:g> pristupa uređaju <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Želite li da dozvolite da <xliff:g id="APPLICATION">%1$s</xliff:g> pristupa uređaju <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Želite li da otvorite aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g> da biste koristili uređaj <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Želite li da otvorite aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g> da biste koristili uređaj <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Instalirane aplikacije ne funkcionišu sa ovim USB pomoćnim uređajem. Saznajte više o njemu na adresi <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB pomoćni uređaj"</string>
<string name="label_view" msgid="6304565553218192990">"Prikaži"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Koristi podrazumevano za ovaj USB uređaj"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Koristi podrazumevano za ovaj USB dodatak"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Uvek otvaraj aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g> kada je uređaj <xliff:g id="USB_DEVICE">%2$s</xliff:g> povezan"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Uvek otvaraj aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g> kada je uređaj <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> povezan"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Želite li da dozvolite otklanjanje USB grešaka?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Digitalni otisak RSA ključa ovog računara je:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Uvek dozvoli sa ovog računara"</string>
@@ -244,8 +244,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Podaci su pauzirani"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Dostigli se ograničenje za podatke koje ste podesili. Više ne koristite mobilne podatke.\n\nAko nastavite, možda će važiti tarife za potrošnju podataka."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internet veze"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi je povezan"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Traži se GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokaciju je podesio GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Ima aktivnih zahteva za lokaciju"</string>
@@ -403,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Želite li da uklonite korisnika?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Sve aplikacije i podaci ovog korisnika će biti izbrisani."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Ukloni"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Štednja baterije je uključena"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Ušteda baterije je uključena"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Smanjuje performanse i pozadinske podatke"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Isključi štednju baterije"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Isključi Uštedu baterije"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> će početi da snima sve što se prikazuje na ekranu."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ne prikazuj ponovo"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Obriši sve"</string>
@@ -588,8 +586,8 @@
<item quantity="other">%d minuta</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Potrošnja baterije"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Ušteda baterije nije dostupna tokom punjenja"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Ušteda baterije"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ušteda baterije nije dostupna tokom punjenja"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Ušteda baterije"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Smanjuje performanse i pozadinske podatke"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Dugme <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Taster Početna"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index e2ee4ea..c077c03 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -36,14 +36,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Апавяшчэнні"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Нізкі ўзровень зараду акумулятара"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Засталося <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Засталося <xliff:g id="PERCENTAGE">%s</xliff:g>. Уключана эканомія зараду."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Засталося <xliff:g id="PERCENTAGE">%s</xliff:g>. Уключана эканомія зараду."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-зарадка не падтрымліваецца.\nКарыстайцеся толькі зарадкай для прылады."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Зарадка па USB не падтрымліваецца."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Выкарыстоўвайце толькі зарадную прыладу ў камплекце."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Налады"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Уключыць эканомію зараду?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Уключыць рэжым эканоміі зараду?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Уключыць"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Уключыць рэжым эканоміі зараду"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Уключыць рэжым эканоміі зараду"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Налады"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Аўтаматычны паварот экрана"</string>
@@ -53,21 +53,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Прывязаныя праз Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Налада метадаў уводу"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Фізічная клавіятура"</string>
- <!-- no translation found for usb_device_permission_prompt (1825685909587559679) -->
- <skip />
- <!-- no translation found for usb_accessory_permission_prompt (2465531696941369047) -->
- <skip />
- <!-- no translation found for usb_device_confirm_prompt (7440562274256843905) -->
- <skip />
- <!-- no translation found for usb_accessory_confirm_prompt (4333670517539993561) -->
- <skip />
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Дазволіць праграме <xliff:g id="APPLICATION">%1$s</xliff:g> доступ да прылады <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Дазволіць праграме <xliff:g id="APPLICATION">%1$s</xliff:g> доступ да прылады <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Адкрыць праграму <xliff:g id="APPLICATION">%1$s</xliff:g> для працы з прыладай <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Адкрыць праграму <xliff:g id="APPLICATION">%1$s</xliff:g> для працы з прыладай <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Няма ўсталяв. прыкл. для працы з гэтай прыл. USB. Больш падраб. пра гэтую прыл.: <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB-прылада"</string>
<string name="label_view" msgid="6304565553218192990">"Прагляд"</string>
- <!-- no translation found for always_use_device (4015357883336738417) -->
- <skip />
- <!-- no translation found for always_use_accessory (3257892669444535154) -->
- <skip />
+ <string name="always_use_device" msgid="4015357883336738417">"Заўсёды адкрываць <xliff:g id="APPLICATION">%1$s</xliff:g>, калі падключана прылада <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Заўсёды адкрываць <xliff:g id="APPLICATION">%1$s</xliff:g>, калі падключаны аксесуар <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Дазволіць адладку USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Адбiтак ключа RSA на гэтым камп\'ютары:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Заўсёды дазваляць з гэтага камп\'ютара"</string>
@@ -253,8 +247,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Перадача даных прыпынена"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Ліміт даных, які вы задалі, быў дасягнуты. Вы больш не выкарыстоўваеце мабільную перадачу даных.\n\nКалі вы ўзновіце карыстанне, можа спаганяцца плата за выкарыстанне трафіка."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Узнавіць"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Няма падключэння да Iнтэрнэту"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi падключаны"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Пошук GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Месца задана праз GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Ёсць актыўныя запыты пра месцазнаходжанне"</string>
@@ -413,9 +405,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Выдаліць карыстальніка?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Усе праграмы і даныя гэтага карыстальніка будуць выдалены."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Выдаліць"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Рэжым эканоміі зараду ўключаны"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Рэжым эканоміі зараду ўключаны"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Памяншае прадукцыйнасць і фонавую перадачу даных"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Адключыць рэжым эканоміі зараду"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Адключыць рэжым эканоміі зараду"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> атрымае доступ да ўсяго, што адлюстроўваецца на вашым экране."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Не паказваць зноў"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Ачысціць усё"</string>
@@ -602,8 +594,8 @@
<item quantity="other">%d хвіліны</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Выкарыстанне зараду"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Эканомія зараду акумулятара недаступная падчас зарадкі"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Эканомія зараду акумулятара"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Эканомія зараду акумулятара недаступная падчас зарадкі"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Эканомія зараду"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Памяншае прадукцыйнасць і фонавую перадачу даных"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Кнопка <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-bg/config.xml b/packages/SystemUI/res/values-bg/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-bg/config.xml
+++ b/packages/SystemUI/res/values-bg/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 35b5177..c567adf 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Известия"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Батерията е изтощена"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Остава/т <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Остава/т <xliff:g id="PERCENTAGE">%s</xliff:g>. Включен е режимът за запазване на батерията."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Остава/т <xliff:g id="PERCENTAGE">%s</xliff:g>. Режимът за запазване на батерията е включен."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Не се поддържа зареждане през USB.\nИзползвайте само доставеното зарядно устройство."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Зареждането през USB не се поддържа."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Използвайте само предоставеното зарядно устройство."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Настройки"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Да се включи ли режимът за запазване на батерията?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Да се включи ли режимът за запазване на батерията?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Включване"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Включване на режима за запазване на батерията"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Включване на режима за запазване на батерията"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Настройки"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Авт. завъртане на екрана"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth има връзка с тетъринг"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Методи на въвеждане: Настройка"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Физическа клавиатура"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Да се разреши ли на приложението <xliff:g id="APPLICATION">%1$s</xliff:g> достъп до USB устройството?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Да се разреши ли на приложението <xliff:g id="APPLICATION">%1$s</xliff:g> достъп до аксесоара за USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Да се отвори ли <xliff:g id="ACTIVITY">%1$s</xliff:g>, когато това USB устройство е свързано?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Да се отвори ли <xliff:g id="ACTIVITY">%1$s</xliff:g>, когато този аксесоар за USB е свързан?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Да се разреши ли на <xliff:g id="APPLICATION">%1$s</xliff:g> достъп до <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Да се разреши ли на <xliff:g id="APPLICATION">%1$s</xliff:g> достъп до <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Да се използва ли <xliff:g id="APPLICATION">%1$s</xliff:g> за работата с/ъс <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Да се използва ли <xliff:g id="APPLICATION">%1$s</xliff:g> за работата с/ъс <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Инстал. приложения не работят с този аксесоар за USB. Научете повече на адрес <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Аксесоар за USB"</string>
<string name="label_view" msgid="6304565553218192990">"Преглед"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Използване по подразб. за това USB устройство"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Използване по подразб. за този аксесоар за USB"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="APPLICATION">%1$s</xliff:g> да се отваря винаги при връзка с/ъс <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="APPLICATION">%1$s</xliff:g> да се отваря винаги при връзка с/ъс <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Да се разреши ли отстраняването на грешки през USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Отпечатъкът на RSA ключа на компютъра е:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Винаги да се разрешава от този компютър"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Данните са поставени на пауза"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Достигнахте зададеното от вас ограничение за данните. Вече не използвате мобилната мрежа.\n\nАко възобновите връзката с нея, може да бъдете таксувани за пренос на данни."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Възобновяване"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Няма връзка с интернет"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: Има връзка"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Търси се GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Местоположението е зададено от GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Активни заявки за местоположение"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Да се премахне ли потребителят?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Всички приложения и данни на този потребител ще бъдат изтрити."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Премахване"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Режимът за запазване на батерията е включен"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Режимът за запазване на батерията е включен"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Намалява ефективността и данните на заден план"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Изключване на режима за запазване на батерията"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Изключване на режима за запазване на батерията"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ще започне да заснема всичко, което се показва на екрана ви."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Да не се показва отново"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Изчистване на всички"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d минута</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Ползв. на батерията"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Режимът за запазване на батерията не работи при зареждане"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Режим за запазване на батерията"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Режимът за запазване на батерията не е налице при зареждане"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Режим за запазване на батерията"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Намалява ефективността и данните на заден план"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Бутон „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Начало"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 581ac73..5770779 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"বিজ্ঞপ্তিগুলি"</string>
<string name="battery_low_title" msgid="6456385927409742437">"ব্যাটারি কম"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> অবশিষ্ট আছে"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> অবশিষ্ট আছে৷ ব্যাটারি সাশ্রয়কারী চালু আছে৷"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> অবশিষ্ট আছে। ব্যাটারি সেভার চালু আছে।"</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB চার্জিং সমর্থিত নয়৷\nকেবলমাত্র সরবহারকৃত চার্জার ব্যবহার করুন৷"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB চার্জিং সমর্থিত নয়।"</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"শুধুমাত্র সরবরাহকৃত চার্জার ব্যবহার করুন।"</string>
<string name="battery_low_why" msgid="4553600287639198111">"সেটিংস"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"ব্যাটারি সঞ্চয়কারী চালু করবেন?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"ব্যাটারি সেভার চালু করবেন?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"চালু করুন"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"ব্যাটারি সঞ্চয়কারী চালু"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"ব্যাটারি সেভার চালু করুন"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"সেটিংস"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"ওয়াই-ফাই"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"স্বতঃ-ঘূর্ণায়মান স্ক্রিন"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ডেট বিরতি দেওয়া হয়েছে"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"আপনার সেট করা ডেটার সীমা ফুরিয়ে গেছে। আপনি এখন আর মোবাইল ডেটা ব্যবহার করতে পারবেন না।\n\nযদি আপনি আবার শুরু করেন, ডেটা ব্যবহারের জন্য মূল্য প্রযোজ্য হতে পারে।"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"পুনঃসূচনা করুন"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"কোনো ইন্টারনেট সংযোগ নেই"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ওয়াই-ফাই সংযুক্ত হয়েছে"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS এর জন্য অনুসন্ধান করা হচ্ছে"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS এর দ্বারা সেট করা অবস্থান"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"অবস্থান অনুরোধ সক্রিয় রয়েছে"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"ব্যবহারকারী সরাবেন?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"এই ব্যবহারকারীর সমস্ত অ্যাপ্লিকেশান ও ডেটা মুছে ফেলা হবে।"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"সরান"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"ব্যাটারি সেভার চালু রয়েছে"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"ব্যাটারি সেভার চালু আছে"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"কার্য-সম্পাদনা ও পশ্চাদপট ডেটাকে কমিয়ে দেয়"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ব্যাটারি সঞ্চয়কারী বন্ধ করুন"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"ব্যাটারি সেভার বন্ধ করুন"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> আপনার স্ক্রীনে দেখানো সব কিছু ক্যাপচার করা শুরু করবে।"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"আর দেখাবেন না"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"সবকিছু সাফ করুন"</string>
@@ -582,8 +580,8 @@
<item quantity="other">%d মিনিট</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"ব্যাটারির ব্যবহার"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"চার্জ করার সময় ব্যাটারি সেভার কাজ করে না"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"ব্যাটারি সেভার"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"চার্জ করার সময় ব্যাটারি সেভার উপলব্ধ নয়"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"ব্যাটারি সেভার"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"কার্য-সম্পাদনা ও পশ্চাদপট ডেটাকে কমিয়ে দেয়"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> বোতাম"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"হোম"</string>
@@ -732,10 +730,10 @@
<string name="pip_skip_to_prev" msgid="1955311326688637914">"পিছনে যাওয়ার জন্য এড়িয়ে যান"</string>
<string name="thermal_shutdown_title" msgid="4458304833443861111">"আপনার ফোন গরম হওয়ার জন্য বন্ধ হয়ে গেছে"</string>
<string name="thermal_shutdown_message" msgid="9006456746902370523">"আপনার ফোন এখন ঠিক-ঠাক চলছে"</string>
- <string name="thermal_shutdown_dialog_message" msgid="566347880005304139">"আপনার ফোন খুব বেশি গরম হয়েছিল বলে ঠান্ডা হওয়ার জন্য বন্ধ হয়ে গেছে। আপনার ফোন ঠিক-ঠাক ভাবে চলছে না।\n\nআপনার ফোন খুব বেশি গরম হয়ে যাবে যদি আপনি:\n •এমন অ্যাপ ব্যবহার করলে যেটি আপনার ডিভাইসের রিসোর্স বেশি ব্যবহার করে (যেমন গেমিং, ভিডিও বা নেভিগেশন অ্যাপ)\n • বড় ফাইল ডাউনলোড বা আপলোড করলে\n • বেশি তাপমাত্রায় আপনার ফোন ব্যবহার করলে"</string>
+ <string name="thermal_shutdown_dialog_message" msgid="566347880005304139">"আপনার ফোন খুব বেশি গরম হয়েছিল বলে ঠাণ্ডা হওয়ার জন্য বন্ধ হয়ে গেছে। আপনার ফোন ঠিক-ঠাক ভাবে চলছে না।\n\nআপনার ফোন খুব বেশি গরম হয়ে যাবে যদি আপনি:\n •এমন অ্যাপ ব্যবহার করলে যেটি আপনার ডিভাইসের রিসোর্স বেশি ব্যবহার করে (যেমন গেমিং, ভিডিও বা নেভিগেশন অ্যাপ)\n • বড় ফাইল ডাউনলোড বা আপলোড করলে\n • বেশি তাপমাত্রায় আপনার ফোন ব্যবহার করলে"</string>
<string name="high_temp_title" msgid="4589508026407318374">"ফোনটি গরম হচ্ছে"</string>
- <string name="high_temp_notif_message" msgid="5642466103153429279">"ফোনটি ঠান্ডা হওয়ার সময় কিছু বৈশিষ্ট্য সীমিত হতে পারে"</string>
- <string name="high_temp_dialog_message" msgid="6840700639374113553">"আপনার ফোনটি নিজে থেকেই ঠান্ডা হওয়ার চেষ্টা করবে৷ আপনি তবুও আপনার ফোন ব্যবহার করতে পারেন, কিন্তু এটি একটু ধীরে চলতে পারে৷\n\nআপনার ফোনটি পুরোপুরি ঠান্ডা হয়ে গেলে এটি স্বাভাবিকভাবে চলবে৷"</string>
+ <string name="high_temp_notif_message" msgid="5642466103153429279">"ফোনটি ঠাণ্ডা হওয়ার সময় কিছু বৈশিষ্ট্য সীমিত হতে পারে"</string>
+ <string name="high_temp_dialog_message" msgid="6840700639374113553">"আপনার ফোনটি নিজে থেকেই ঠাণ্ডা হওয়ার চেষ্টা করবে৷ আপনি তবুও আপনার ফোন ব্যবহার করতে পারেন, কিন্তু এটি একটু ধীরে চলতে পারে৷\n\nআপনার ফোনটি পুরোপুরি ঠাণ্ডা হয়ে গেলে এটি স্বাভাবিকভাবে চলবে৷"</string>
<string name="lockscreen_shortcut_left" msgid="2182769107618938629">"বাঁদিকের শর্টকাট"</string>
<string name="lockscreen_shortcut_right" msgid="3328683699505226536">"ডানদিকের শর্টকাট"</string>
<string name="lockscreen_unlock_left" msgid="2043092136246951985">"বাঁদিকের শর্টকাট দিয়েও আনলক করা যায়"</string>
@@ -758,7 +756,8 @@
<string name="instant_apps" msgid="6647570248119804907">"ঝটপট অ্যাপ"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"ঝটপট অ্যাপ ইনস্টল করার প্রয়োজন হয় না।"</string>
<string name="app_info" msgid="6856026610594615344">"অ্যাপের তথ্য"</string>
- <string name="go_to_web" msgid="1106022723459948514">"ওয়েবে যান"</string>
+ <!-- no translation found for go_to_web (2650669128861626071) -->
+ <skip />
<string name="mobile_data" msgid="7094582042819250762">"মোবাইল ডেটা"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"ওয়াই ফাই বন্ধ আছে"</string>
<string name="bt_is_off" msgid="2640685272289706392">"ব্লুটুথ বন্ধ আছে"</string>
diff --git a/packages/SystemUI/res/values-bs/config.xml b/packages/SystemUI/res/values-bs/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-bs/config.xml
+++ b/packages/SystemUI/res/values-bs/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 5d621cb..530c1a8 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -35,14 +35,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Obavještenja"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Baterija je skoro prazna"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Preostalo <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Preostalo <xliff:g id="PERCENTAGE">%s</xliff:g>. Uključena je štednja baterije."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Preostalo <xliff:g id="PERCENTAGE">%s</xliff:g>. Uključena je Ušteda baterije."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB punjenje nije podržano.\nKoristite samo priloženi punjač."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Punjenje pomoću USB-a nije podržano."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Koristite isključivo priloženi punjač."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Postavke"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Želite li uključiti štednju baterije?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Uključiti Uštedu baterije?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Uključi"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Uključi štednju baterije"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Uključi Uštedu baterije"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Postavke"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatsko rotiranje ekrana"</string>
@@ -52,15 +52,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Dijeljenje Bluetooth veze"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Postavljanje načina unosa"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fizička tastatura"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Dozvoliti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> pristup USB uređaju?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Dozvoliti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> pristup USB perifernom uređaju?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Otvoriti <xliff:g id="ACTIVITY">%1$s</xliff:g> kada je ovaj USB uređaj spojen?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Otvoriti <xliff:g id="ACTIVITY">%1$s</xliff:g> kada se poveže ovaj USB periferni uređaj?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Dozvoliti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> pristup uređaju: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Dozvoliti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> pristup dodatku: <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Otvoriti aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g> za upravljanje uređajem: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Otvoriti aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g> za upravljanje dodatkom: <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Nema instaliranih aplikacija za ovaj USB uređaj. Saznajte više o uređaju na <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB periferni uređaj"</string>
<string name="label_view" msgid="6304565553218192990">"Prikaži"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Koristiti kao zadanu opciju za ovaj USB uređaj"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Koristiti kao zadanu opciju za ovaj USB uređaj"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Uvijek otvori aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g> kada se poveže <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Uvijek otvori aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g> kada se poveže <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Omogućiti otklanjanje grešaka putem uređaja spojenog na USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"RSA otisak prsta za otključavanje računara je: \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Uvijek dozvoli sa ovog računara"</string>
@@ -244,8 +244,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Prijenos podataka je pauziran"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Dostigli ste ograničenje za prijenos podataka koje ste postavili. Više ne koristite mobilne podatke.\n\nUkoliko nastavite koristiti mobilne podatke, mogući su troškovi za prijenos podataka."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Niste povezani na internet"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi veza aktivna"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Traženje GPS signala"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokacija utvrđena GPS signalom"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Aktiviran je zahtjev za lokaciju"</string>
@@ -333,7 +331,7 @@
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Sve ste obrisali"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"kačenje ekrana"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"pretraga"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"pretraživanje"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacija <xliff:g id="APP">%s</xliff:g> nije pokrenuta."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> je onemogućena u sigurnom načinu rada."</string>
<string name="recents_stack_action_button_label" msgid="6593727103310426253">"Obriši sve"</string>
@@ -341,9 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podjela po horizontali"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podjela po vertikali"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Prilagođena podjela"</string>
- <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Podijeli ekran nagore"</string>
- <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Podijeli ekran nalijevo"</string>
- <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Podijeli ekran nadesno"</string>
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Dijeli ekran nagore"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Dijeli ekran nalijevo"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Dijeli ekran nadesno"</string>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjeno"</string>
<string name="expanded_header_battery_charging" msgid="205623198487189724">"Punjenje"</string>
<string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Do kraja punjenja preostalo <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
@@ -403,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Zaista želite ukloniti korisnika?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Sve aplikacije i podaci ovog korisnika bit će izbrisani."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Ukloni"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Štednja baterije je uključena"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Uključena je Ušteda baterije"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Minimizira rad i prijenos podataka u pozadini"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Isključi štednju baterije"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Isključi Uštedu baterije"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> će početi snimati sve što se prikaže na ekranu."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ne prikazuj opet"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Očisti sve"</string>
@@ -505,7 +503,7 @@
<string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Dodirnite da isključite zvuk."</string>
<string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Prikazane kontrole jačine zvuka za: %s. Prevucite prema gore za odbacivanje."</string>
<string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Kontrole jačine zvuka sakrivene"</string>
- <string name="system_ui_tuner" msgid="708224127392452018">"Podešavač za korisničko sučelje sistema"</string>
+ <string name="system_ui_tuner" msgid="708224127392452018">"Podešavač za korisnički interfejs sistema"</string>
<string name="show_battery_percentage" msgid="5444136600512968798">"Prikaži ugrađeni postotak baterije"</string>
<string name="show_battery_percentage_summary" msgid="3215025775576786037">"Prikazuje postotak nivoa baterije unutar ikone na statusnoj traci kada se baterija ne puni"</string>
<string name="quick_settings" msgid="10042998191725428">"Brze postavke"</string>
@@ -528,12 +526,12 @@
<string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Pristupna tačka"</string>
<string name="accessibility_managed_profile" msgid="6613641363112584120">"Profil za posao"</string>
<string name="tuner_warning_title" msgid="7094689930793031682">"Zabava za neke, ali ne za sve"</string>
- <string name="tuner_warning" msgid="8730648121973575701">"Podešavač za korisničko sučelje sistema vam omogućava dodatne načine da podesite i prilagodite Androidovo sučelje. Ove eksperimentalne funkcije se u budućim verzijama mogu mijenjati, kvariti ili nestati. Budite oprezni."</string>
+ <string name="tuner_warning" msgid="8730648121973575701">"Podešavač za korisnički interfejs sistema vam omogućava dodatne načine da podesite i prilagodite Androidov interfejs. Ove eksperimentalne funkcije se u budućim verzijama mogu mijenjati, kvariti ili nestati. Budite oprezni."</string>
<string name="tuner_persistent_warning" msgid="8597333795565621795">"Ove eksperimentalne funkcije se u budućim verzijama mogu mijenjati, kvariti ili nestati. Budite oprezni."</string>
<string name="got_it" msgid="2239653834387972602">"Razumijem"</string>
- <string name="tuner_toast" msgid="603429811084428439">"Čestitamo! Podešavač za korisničko sučelje sistema je dodan u Postavke"</string>
+ <string name="tuner_toast" msgid="603429811084428439">"Čestitamo! Podešavač za korisnički interfejs sistema je dodan u Postavke"</string>
<string name="remove_from_settings" msgid="8389591916603406378">"Ukloni iz Postavki"</string>
- <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Želite li ukloniti Podešavač za korisničko sučelje sistema iz Postavki i prestati koristiti sve njegove funkcije?"</string>
+ <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Želite li ukloniti Podešavač za korisnički interfejs sistema iz Postavki i prestati koristiti sve njegove funkcije?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Aplikacija nije instalirana na uređaju"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Prikaži sekunde"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Prikaži sekunde na statusnoj traci. Može skratiti trajanje baterije."</string>
@@ -590,8 +588,8 @@
<item quantity="other">%d minuta</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Potrošnja baterije"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Ušteda baterije je isključena za vrijeme punjenja"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Ušteda baterije"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ušteda baterije je isključena prilikom punjenja"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Ušteda baterije"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Ograničava rad i prijenos podataka u pozadini"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Dugme <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Tipka za početak"</string>
@@ -766,7 +764,8 @@
<string name="instant_apps" msgid="6647570248119804907">"Instant-aplikacije"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Za instant aplikacije nije potrebna instalacija"</string>
<string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Idite na internet"</string>
+ <!-- no translation found for go_to_web (2650669128861626071) -->
+ <skip />
<string name="mobile_data" msgid="7094582042819250762">"Mobilni podaci"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi veza je isključena"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth je isključen"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index dcf8336..1c5fe90 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificacions"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Queda poca bateria"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>."</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>. L\'estalvi de bateria està activat."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>. La funció Estalvi de bateria està activada."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Càrrega d\'USB no admesa.\nUtilitza només el carregador proporcionat."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"La càrrega per USB no és compatible."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Fes servir només el carregador proporcionat amb el dispositiu."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Configuració"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Vols activar l\'estalvi de bateria?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Vols activar la funció Estalvi de bateria?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Activa"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Activa l\'estalvi de bateria"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Activa la funció Estalvi de bateria"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configuració"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Gira pantalla automàticament"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Les dades estan aturades"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"S\'ha assolit el límit de dades establert. Ja no estàs utilitzant dades mòbils.\n\nSi reprens l\'ús de les dades, es poden aplicar càrrecs."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reprèn"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No hi ha connexió a Internet"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: connectada"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"S\'està cercant un GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"S\'ha establert la ubicació per GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Sol·licituds d\'ubicació actives"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Vols suprimir l\'usuari?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Totes les aplicacions i les dades d\'aquest usuari se suprimiran."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Suprimeix"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Estalvi de bateria activat"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"S\'ha activat la funció Estalvi de bateria"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Redueix el rendiment i l\'ús de les dades en segon pla."</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactiva l\'estalvi de bateria"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Desactiva la funció Estalvi de bateria"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> començarà a gravar tot el que es mostri a la pantalla."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"No ho tornis a mostrar"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Esborra-ho tot"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d minut</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Consum de la bateria"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"La funció Estalvi de bateria no està disponible durant la càrrega"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Estalvi de bateria"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"La funció Estalvi de bateria no està disponible durant la càrrega"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Estalvi de bateria"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Redueix el rendiment i les dades en segon pla"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Botó <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Inici"</string>
diff --git a/packages/SystemUI/res/values-cs/config.xml b/packages/SystemUI/res/values-cs/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-cs/config.xml
+++ b/packages/SystemUI/res/values-cs/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index e014af6..b1cddfb 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -36,14 +36,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Oznámení"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Baterie je slabá"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Zbývá <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Zbývá <xliff:g id="PERCENTAGE">%s</xliff:g>. Spořič baterie je zapnutý."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Zbývá <xliff:g id="PERCENTAGE">%s</xliff:g>. Spořič baterie je zapnutý."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Nabíjení pomocí rozhraní USB není podporováno.\nPoužívejte pouze nabíječku, která byla dodána se zařízením."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Nabíjení přes USB není podporováno."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Používejte pouze nabíječku, která je součástí balení."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Nastavení"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Zapnout úsporu baterie?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Zapnout spořič baterie?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Zapnout"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Zapnout úsporu baterie"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Zapnout spořič baterie"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavení"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Autom. otočení obrazovky"</string>
@@ -53,15 +53,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Datové připojení Bluetooth se sdílí"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Nastavit metody zadávání"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fyzická klávesnice"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Povolit aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g> přístup k zařízení USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Povolit aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g> přístup k perifernímu zařízení USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Chcete při připojení tohoto zařízení USB otevřít aplikaci <xliff:g id="ACTIVITY">%1$s</xliff:g>?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Chcete při připojení tohoto periferního zařízení USB otevřít aplikaci <xliff:g id="ACTIVITY">%1$s</xliff:g>?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Povolit aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g> přístup k zařízení <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Povolit aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g> přístup k zařízení <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Otevřít aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g> ke správě zařízení <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Otevřít aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g> ke správě zařízení <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Žádná nainstalovaná aplikace s tímto zařízením USB nepracuje. Info. najdete na <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Periferní zařízení USB"</string>
<string name="label_view" msgid="6304565553218192990">"Zobrazit"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Pro toto zařízení USB použít jako výchozí"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Pro toto periferní zařízení USB použít jako výchozí"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Když bude připojeno zařízení <xliff:g id="USB_DEVICE">%2$s</xliff:g>, vždy otevřít <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Když bude připojeno zařízení <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>, vždy otevřít <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Povolit ladění USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Digitální otisk RSA počítače je:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Vždy povolit z tohoto počítače"</string>
@@ -247,8 +247,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data jsou pozastavena"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Byl dosažen limit dat. Mobilní datové připojení již nepoužíváte.\n\nPokud jej obnovíte, mohou vám být účtovány poplatky za využití dat."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Pokračovat"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Žádné přip. k internetu"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: připojeno"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Vyhledávání satelitů GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Poloha nastavena pomocí systému GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Aktivní žádosti o polohu"</string>
@@ -407,9 +405,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Odstranit uživatele?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Veškeré aplikace a data tohoto uživatele budou smazána."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Odstranit"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Režim Úspora baterie je zapnutý."</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Spořič baterie je zapnutý"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Omezuje výkon a data na pozadí"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Vypnout úsporu baterie"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Vypnout spořič baterie"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikace <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> začne zaznamenávat vše, co je zobrazeno na obrazovce."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Tuto zprávu příště nezobrazovat"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Smazat vše"</string>
@@ -596,8 +594,8 @@
<item quantity="one">%d minuta</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Využití baterie"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Spořič baterie při nabíjení není k dispozici"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Spořič baterie"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Spořič baterie při nabíjení není k dispozici."</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Spořič baterie"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Omezuje výkon a data na pozadí"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Tlačítko <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
@@ -647,9 +645,9 @@
<string name="volume_up_silent" msgid="7141255269783588286">"Při zvýšení hlasitosti ukončit režim Nerušit"</string>
<string name="battery" msgid="7498329822413202973">"Baterie"</string>
<string name="clock" msgid="7416090374234785905">"Hodiny"</string>
- <string name="headset" msgid="4534219457597457353">"Náhlavní souprava"</string>
+ <string name="headset" msgid="4534219457597457353">"Sluchátka"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Sluchátka připojena"</string>
- <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Náhlavní souprava připojena"</string>
+ <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Sluchátka připojena"</string>
<string name="data_saver" msgid="5037565123367048522">"Spořič dat"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Spořič dat je zapnutý"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Spořič dat je vypnutý"</string>
diff --git a/packages/SystemUI/res/values-da/config.xml b/packages/SystemUI/res/values-da/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-da/config.xml
+++ b/packages/SystemUI/res/values-da/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 58e9a2f..e4198f3 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Underretninger"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Batteriniveauet er lavt"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> tilbage"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> tilbage. Batterisparefunktionen er slået til."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> tilbage. Batterisparefunktion er aktiveret."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Opladning via USB understøttes ikke.\nBrug kun den medfølgende oplader."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB-opladning understøttes ikke."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Brug kun den oplader, der føler med."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Indstillinger"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Vil du aktivere batterisparefunktionen?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Vil du aktivere Batterisparefunktion?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Aktivér"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Aktivér batterisparefunktion"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Aktivér Batterisparefunktion"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Indstillinger"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatisk skærmrotation"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Netdeling via Bluetooth anvendt"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfigurer inputmetoder"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fysisk tastatur"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Tillad, at appen <xliff:g id="APPLICATION">%1$s</xliff:g> kan få adgang til USB-enheden?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vil du tillade, at appen <xliff:g id="APPLICATION">%1$s</xliff:g> får adgang til USB-enheden?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vil du åbne <xliff:g id="ACTIVITY">%1$s</xliff:g>, når denne USB-enhed er tilsluttet?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Vil du åbne <xliff:g id="ACTIVITY">%1$s</xliff:g>, når dette USB-ekstraudstyr er tilsluttet?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Vil du give <xliff:g id="APPLICATION">%1$s</xliff:g> adgang til <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Vil du give <xliff:g id="APPLICATION">%1$s</xliff:g> adgang til <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Vil du åbne <xliff:g id="APPLICATION">%1$s</xliff:g> til håndtering af <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Vil du åbne <xliff:g id="APPLICATION">%1$s</xliff:g> til håndtering af <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Ingen installerede apps fungerer med USB-enheden. Få oplysninger om enheden på <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB-ekstraudstyr"</string>
<string name="label_view" msgid="6304565553218192990">"Vis"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Brug som standard til denne USB-enhed"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Brug som standard til dette USB-tilbehør"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Åbn altid <xliff:g id="APPLICATION">%1$s</xliff:g>, når <xliff:g id="USB_DEVICE">%2$s</xliff:g> er tilsluttet"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Åbn altid <xliff:g id="APPLICATION">%1$s</xliff:g>, når <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> er tilsluttet"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Vil du tillade USB-fejlretning?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Fingeraftrykket for computerens RSA-nøgle er:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Tillad altid fra denne computer"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data er sat på pause"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Din angivne datagrænse er nået, og du bruger ikke længere mobildata.\n\nHvis du fortsætter, bliver du muligvis opkrævet betaling for dit dataforbrug."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Genoptag"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen internetforb."</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi er forbundet"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Søger efter GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Placeringen er angivet ved hjælp af GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Aktive placeringsanmodninger"</string>
@@ -254,7 +252,7 @@
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> underretning mere i gruppen.</item>
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> underretninger mere i gruppen.</item>
</plurals>
- <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Indstillinger for underretninger"</string>
+ <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Underretningsindstillinger"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Indstillinger for <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skærmen roterer automatisk."</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skærmen er nu låst i liggende retning."</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Vil du fjerne brugeren?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Alle apps og data for denne bruger slettes."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Fjern"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Batterisparefunktion er slået til"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Batterisparefunktion er aktiveret"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reducerer ydeevne og baggrundsdata"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Deaktiver batterisparefunktion"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Deaktiver Batterisparefunktion"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vil begynde at optage alt, hvad der vises på din skærm."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Vis ikke igen"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Ryd alt"</string>
@@ -582,8 +580,8 @@
<item quantity="other">%d minutter</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Batteriforbrug"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Batterisparefunktionen er ikke tilgængelig under opladning"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Batterisparefunktion"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterisparefunktionen er ikke tilgængelig under opladning"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Batterisparefunktion"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reducerer ydeevne og baggrundsdata"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g>-knap"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-de/config.xml b/packages/SystemUI/res/values-de/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-de/config.xml
+++ b/packages/SystemUI/res/values-de/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 2f615fe..e9c2f26 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Benachrichtigungen"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Akku ist schwach"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> verbleibend"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> verbleibend. Der Energiesparmodus ist aktiviert."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Noch <xliff:g id="PERCENTAGE">%s</xliff:g>. Der Energiesparmodus ist aktiviert."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-Aufladung wird nicht unterstützt.\nVerwende das mitgelieferte Aufladegerät."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Laden per USB wird nicht unterstützt."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Verwende nur das im Lieferumfang enthaltene Ladegerät."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Einstellungen"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Energiesparmodus aktivieren?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Energiesparmodus aktivieren?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Aktivieren"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Energiesparmodus aktivieren"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Energiesparmodus aktivieren"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Einstellungen"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WLAN"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Bildschirm automatisch drehen"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth-Tethering aktiv"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Eingabemethoden festlegen"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Physische Tastatur"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"App <xliff:g id="APPLICATION">%1$s</xliff:g> Zugriff auf USB-Gerät gewähren?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"App <xliff:g id="APPLICATION">%1$s</xliff:g> Zugriff auf USB-Zubehör gewähren?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"<xliff:g id="ACTIVITY">%1$s</xliff:g> öffnen, wenn dieses USB-Gerät verbunden ist?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"<xliff:g id="ACTIVITY">%1$s</xliff:g> öffnen, wenn dieses USB-Zubehör verbunden ist?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> den Zugriff auf <xliff:g id="USB_DEVICE">%2$s</xliff:g> gewähren?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> den Zugriff auf <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> gewähren?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Für <xliff:g id="USB_DEVICE">%2$s</xliff:g> <xliff:g id="APPLICATION">%1$s</xliff:g> öffnen?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Für <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> <xliff:g id="APPLICATION">%1$s</xliff:g> öffnen?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Keine installierten Apps für dieses USB-Zubehör. Weitere Informationen unter <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB-Zubehör"</string>
<string name="label_view" msgid="6304565553218192990">"Anzeigen"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Standardmäßig für dieses USB-Gerät verwenden"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Standardmäßig für dieses USB-Zubehör verwenden"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Beim Anschließen von <xliff:g id="USB_DEVICE">%2$s</xliff:g> immer <xliff:g id="APPLICATION">%1$s</xliff:g> öffnen"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Beim Anschließen von <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> immer <xliff:g id="APPLICATION">%1$s</xliff:g> öffnen"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB-Debugging zulassen?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Der Fingerabdruck des RSA-Schlüssels für diesen Computer lautet: \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Von diesem Computer immer zulassen"</string>
@@ -247,8 +247,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Daten pausiert"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Das von dir festgelegte Datenlimit wurde erreicht. Die mobile Datennutzung wurde deaktiviert.\n\nWenn du weiterhin mobile Daten nutzt, können Gebühren anfallen."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Fortsetzen"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Keine Internetverbindung"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN verbunden"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS wird gesucht..."</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Standort durch GPS festgelegt"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Standortanfragen aktiv"</string>
@@ -405,9 +403,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Nutzer entfernen?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Alle Apps und Daten dieses Nutzers werden gelöscht."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Entfernen"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Energiesparmodus ist aktiviert"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Energiesparmodus ist aktiviert"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduzierung der Leistung und Hintergrunddaten"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Energiesparmodus deaktivieren"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Energiesparmodus deaktivieren"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> nimmt alle auf deinem Bildschirm angezeigten Aktivitäten auf."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Nicht erneut anzeigen"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Alle löschen"</string>
@@ -586,8 +584,8 @@
<item quantity="one">%d Minute</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Akkunutzung"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Der Energiesparmodus ist beim Aufladen nicht verfügbar"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Energiesparmodus"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Der Energiesparmodus ist beim Aufladen nicht verfügbar."</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Energiesparmodus"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduzierung der Leistung und Hintergrunddaten"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Taste <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Pos1"</string>
diff --git a/packages/SystemUI/res/values-el/config.xml b/packages/SystemUI/res/values-el/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-el/config.xml
+++ b/packages/SystemUI/res/values-el/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index ef47851..33df73b 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ειδοποιήσεις"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Χαμηλή στάθμη μπαταρίας"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Απομένουν <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Απομένουν <xliff:g id="PERCENTAGE">%s</xliff:g>. Η λειτουργία εξοικονόμησης μπαταρίας είναι ενεργή."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Απομένουν <xliff:g id="PERCENTAGE">%s</xliff:g>. Η Εξοικονόμηση μπαταρίας είναι ενεργή."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Δεν υποστηρίζεται η φόρτιση USB.\nΧρησιμοποιείτε μόνο τον φορτιστή που παρέχεται."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Δεν υποστηρίζεται η φόρτιση μέσω USB."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Χρήση μόνο του παρεχόμενου φορτιστή."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Ρυθμίσεις"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Να ενεργοποιηθεί η εξοικονόμηση μπαταρίας;"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Να ενεργοποιηθεί η Εξοικονόμηση μπαταρίας;"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Ενεργοποίηση"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Ενερ. της εξοικ/σης μπαταρίας"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Ενεργοποίηση Εξοικονόμησης μπαταρίας"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ρυθμίσεις"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Αυτόματη περιστροφή οθόνης"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Έγινε σύνδεση μέσω Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Ρύθμιση μεθόδων εισαγωγής"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Φυσικό πληκτρολόγιο"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Να επιτρέπεται στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> η πρόσβαση στη συσκευή USB;"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Να επιτρέπεται στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> η πρόσβαση στο αξεσουάρ USB;"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Άνοιγμα του <xliff:g id="ACTIVITY">%1$s</xliff:g> κατά τη σύνδεση αυτής της συσκευής USB;"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Άνοιγμα του <xliff:g id="ACTIVITY">%1$s</xliff:g> κατά τη σύνδεση αυτού του αξεσουάρ USB;"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Να επιτρέπεται η πρόσβαση της εφαρμογής <xliff:g id="APPLICATION">%1$s</xliff:g> στη συσκευή <xliff:g id="USB_DEVICE">%2$s</xliff:g>;"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Να επιτρέπεται η πρόσβαση της εφαρμογής <xliff:g id="APPLICATION">%1$s</xliff:g> στο αξεσουάρ <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>;"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Να ανοίγει η εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> για τη διαχείριση της συσκευής <xliff:g id="USB_DEVICE">%2$s</xliff:g>;"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Να ανοίγει η εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> για τη διαχείριση του αξεσουάρ <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>;"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Δεν έχετε εφαρμογή που να συνεργάζεται με το αξεσουάρ USB. Για περισσότερα: <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Αξεσουάρ USB"</string>
<string name="label_view" msgid="6304565553218192990">"Προβολή"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Χρήση από προεπιλογή για αυτή τη συσκευή USB"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Χρήση από προεπιλογή για αυτό το εξάρτημα USB"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Να ανοίγει πάντα η εφ. <xliff:g id="APPLICATION">%1$s</xliff:g> όταν είναι συνδεδεμένo το <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Να ανοίγει πάντα η εφ. <xliff:g id="APPLICATION">%1$s</xliff:g> όταν είναι συνδεδεμένο το <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Να επιτρέπεται ο εντοπισμός σφαλμάτων USB;"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Το μοναδικό χαρακτηριστικό του κλειδιού RSA είναι:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Να επιτρέπεται πάντα από αυτόν τον υπολογιστή"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Τα δεδομένα τέθηκαν σε παύση"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Συμπληρώθηκε το όριο δεδομένων που έχετε ορίσει. Δεν χρησιμοποιείτε πλέον δεδομένα κινητής τηλεφωνίας.\n\nΑν συνεχίσετε, μπορεί να ισχύσουν χρεώσεις για τη χρήση δεδομένων."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Συνέχιση"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Χωρ. σύνδ. στο Διαδ."</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi συνδεδεμένο"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Αναζήτηση για GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Ρύθμιση τοποθεσίας με GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Τα αιτήματα τοποθεσίας έχουν ενεργοποιηθεί"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Κατάργηση χρήστη;"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Όλες οι εφαρμογές και τα δεδομένα αυτού του χρήστη θα διαγραφούν."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Κατάργηση"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Η Εξοικονόμηση μπαταρίας είναι ενεργή"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Η Εξοικονόμηση μπαταρίας είναι ενεργή"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Μειώνει την απόδοση και τα δεδομένα παρασκηνίου"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Απενερ. εξοικ/σης μπαταρίας"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Απενεργοποίηση Εξοικονόμησης μπαταρίας"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"Θα ξεκινήσει η καταγραφή του περιεχομένου που εμφανίζεται στην οθόνη σας από την εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Να μην εμφανιστεί ξανά"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Διαγραφή όλων"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d λεπτό</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Χρήση της μπαταρίας"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Η Εξοικονόμηση μπαταρίας δεν είναι διαθέσιμη κατά τη διάρκεια της φόρτισης"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Εξοικονόμηση μπαταρίας"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Η εξοικονόμηση μπαταρίας δεν είναι διαθέσιμη κατά τη διάρκεια της φόρτισης"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Εξοικονόμηση μπαταρίας"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Μειώνει την απόδοση και τα δεδομένα παρασκηνίου"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Κουμπί <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 76b21b5..87a0ee5 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Battery is low"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining. Battery saver is on."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining. Battery Saver is on."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB charging not supported.\nUse only the supplied charger."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB charging not supported."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Use only the supplied charger."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Settings"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Turn on battery saver?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Turn on Battery Saver?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Turn on"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Turn on battery saver"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Turn on Battery Saver"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Settings"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Auto-rotate screen"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"The data limit that you set has been reached. You are no longer using mobile data.\n\nIf you resume, charges may apply for data usage."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Searching for GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Location set by GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Location requests active"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Remove user?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"All apps and data of this user will be deleted."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Remove"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Battery Saver is on"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduces performance and background data"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Turn off battery saver"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Turn off Battery Saver"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d minute</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Battery usage"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Battery Saver not available during charging"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Battery Saver"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Battery Saver not available during charging"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Battery Saver"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduces performance and background data"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Button <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 1bc1197..6756f86 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Battery is low"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining. Battery saver is on."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining. Battery Saver is on."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB charging not supported.\nUse only the supplied charger."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB charging not supported."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Use only the supplied charger."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Settings"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Turn on battery saver?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Turn on Battery Saver?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Turn on"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Turn on battery saver"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Turn on Battery Saver"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Settings"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Auto-rotate screen"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"The data limit that you set has been reached. You are no longer using mobile data.\n\nIf you resume, charges may apply for data usage."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Searching for GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Location set by GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Location requests active"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Remove user?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"All apps and data of this user will be deleted."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Remove"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Battery Saver is on"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduces performance and background data"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Turn off battery saver"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Turn off Battery Saver"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d minute</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Battery usage"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Battery Saver not available during charging"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Battery Saver"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Battery Saver not available during charging"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Battery Saver"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduces performance and background data"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Button <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 76b21b5..87a0ee5 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Battery is low"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining. Battery saver is on."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining. Battery Saver is on."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB charging not supported.\nUse only the supplied charger."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB charging not supported."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Use only the supplied charger."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Settings"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Turn on battery saver?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Turn on Battery Saver?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Turn on"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Turn on battery saver"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Turn on Battery Saver"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Settings"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Auto-rotate screen"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"The data limit that you set has been reached. You are no longer using mobile data.\n\nIf you resume, charges may apply for data usage."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Searching for GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Location set by GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Location requests active"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Remove user?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"All apps and data of this user will be deleted."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Remove"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Battery Saver is on"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduces performance and background data"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Turn off battery saver"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Turn off Battery Saver"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d minute</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Battery usage"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Battery Saver not available during charging"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Battery Saver"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Battery Saver not available during charging"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Battery Saver"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduces performance and background data"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Button <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 76b21b5..87a0ee5 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Battery is low"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining. Battery saver is on."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining. Battery Saver is on."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB charging not supported.\nUse only the supplied charger."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB charging not supported."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Use only the supplied charger."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Settings"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Turn on battery saver?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Turn on Battery Saver?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Turn on"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Turn on battery saver"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Turn on Battery Saver"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Settings"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Auto-rotate screen"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"The data limit that you set has been reached. You are no longer using mobile data.\n\nIf you resume, charges may apply for data usage."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Searching for GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Location set by GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Location requests active"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Remove user?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"All apps and data of this user will be deleted."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Remove"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Battery Saver is on"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduces performance and background data"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Turn off battery saver"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Turn off Battery Saver"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d minute</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Battery usage"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Battery Saver not available during charging"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Battery Saver"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Battery Saver not available during charging"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Battery Saver"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduces performance and background data"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Button <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 131e199..1d70422 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Battery is low"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining. Battery saver is on."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining. Battery Saver is on."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB charging not supported.\nUse only the supplied charger."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB charging not supported."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Use only the supplied charger."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Settings"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Turn on battery saver?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Turn on Battery Saver?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Turn on"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Turn on battery saver"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Turn on Battery Saver"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Settings"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Auto-rotate screen"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"The data limit you set has been reached. You are no longer using mobile data.\n\nIf you resume, charges may apply for data usage."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Searching for GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Location set by GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Location requests active"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Remove user?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"All apps and data of this user will be deleted."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Remove"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Battery Saver is on"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduces performance and background data"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Turn off battery saver"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Turn off Battery Saver"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d minute</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Battery usage"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Battery saver not available during charging"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Battery saver"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Battery Saver not available during charging"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Battery Saver"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduces performance and background data"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Button <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/config.xml b/packages/SystemUI/res/values-es-rUS/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-es-rUS/config.xml
+++ b/packages/SystemUI/res/values-es-rUS/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 9dd1b01..c97f7d3 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Batería baja"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería."</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería. La función de ahorro de batería está activada."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Queda <xliff:g id="PERCENTAGE">%s</xliff:g> de batería. El Ahorro de batería está activado."</string>
<string name="invalid_charger" msgid="4549105996740522523">"No admite la carga USB.\nUsa sólo el cargador provisto."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"No se admite la carga por USB."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Usa solo el cargador suministrado."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Configuración"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"¿Activar ahorro de batería?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"¿Activar el Ahorro de batería?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Activar"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Activar ahorro de batería"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Activar el Ahorro de batería"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configuración"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Girar la pantalla automáticamente"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth anclado"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configurar métodos de intro."</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Teclado físico"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"¿Deseas que la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> acceda al dispositivo USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"¿Deseas que la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> acceda al accesorio USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"¿Abrir <xliff:g id="ACTIVITY">%1$s</xliff:g> cuando este dispositivo USB esté conectado?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"¿Abrir <xliff:g id="ACTIVITY">%1$s</xliff:g> cuando este accesorio USB esté conectado?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"¿Deseas permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"¿Deseas permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"¿Deseas abrir <xliff:g id="APPLICATION">%1$s</xliff:g> para usar <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"¿Deseas abrir <xliff:g id="APPLICATION">%1$s</xliff:g> para usar <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Ninguna aplic. funciona con este accesorio USB. Más info. acerca de este en <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Accesorio USB"</string>
<string name="label_view" msgid="6304565553218192990">"Ver"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Se usa de forma predeterminada para este dispositivo USB."</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Se usa de forma predeterminada para este accesorio USB."</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Abrir siempre <xliff:g id="APPLICATION">%1$s</xliff:g> cuando se conecte <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Abrir siempre <xliff:g id="APPLICATION">%1$s</xliff:g> cuando se conecte <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"¿Permitir depuración por USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"La huella digital de tu clave RSA es:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Permitir siempre desde esta computadora"</string>
@@ -245,8 +245,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datos pausados"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Se alcanzó el límite de datos que estableciste. Ya no estás usando datos móviles.\n\nSi reanudas el servicio, es posible que se apliquen cargos."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reanudar"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"La ubicación se estableció por GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Solicitudes de ubicación activas"</string>
@@ -403,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"¿Confirmas que quieres quitar el usuario?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Se borrarán todas las aplicaciones y los datos de este usuario."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Quitar"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Ahorro de batería activado"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"El Ahorro de batería está activado"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce el rendimiento y el uso de datos en segundo plano."</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactivar el ahorro de batería"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Desactivar el Ahorro de batería"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> comenzará la captura de todo lo que se muestre en la pantalla."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"No volver a mostrar"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Borrar todo"</string>
@@ -584,8 +582,8 @@
<item quantity="one">%d minuto</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Uso de la batería"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"El Ahorro de batería no está disponible durante la carga"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Ahorro de batería"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ahorro de batería no está disponible durante la carga"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Ahorro de batería"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce el rendimiento y el uso de datos en segundo plano"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Página principal"</string>
diff --git a/packages/SystemUI/res/values-es/config.xml b/packages/SystemUI/res/values-es/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-es/config.xml
+++ b/packages/SystemUI/res/values-es/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 52e7c51..94467d8 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Nivel de batería bajo"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería. La función de ahorro de batería está activada."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería. Se ha activado la función Ahorro de energía."</string>
<string name="invalid_charger" msgid="4549105996740522523">"No se admite la carga por USB.\nUtiliza solo el cargador proporcionado."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"No se admite la carga por USB."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Utiliza solo el cargador proporcionado."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Ajustes"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"¿Activar ahorro de batería?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"¿Activar Ahorro de batería?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Activar"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Activar ahorro de batería"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Activar Ahorro de batería"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ajustes"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Girar pantalla automáticamente"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth anclado"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configurar métodos de entrada"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Teclado físico"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"¿Permitir que la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> acceda al dispositivo USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"¿Permitir que la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> acceda al accesorio USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"¿Quieres abrir <xliff:g id="ACTIVITY">%1$s</xliff:g> al conectar este dispositivo USB?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"¿Quieres abrir <xliff:g id="ACTIVITY">%1$s</xliff:g> al conectar este accesorio USB?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"¿Quieres permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"¿Quieres permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"¿Quieres abrir <xliff:g id="APPLICATION">%1$s</xliff:g> para utilizar <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"¿Quieres abrir <xliff:g id="APPLICATION">%1$s</xliff:g> para utilizar <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Ninguna aplicación instalada funciona con este accesorio USB. Más información: <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Accesorio USB"</string>
<string name="label_view" msgid="6304565553218192990">"Ver"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Usar de forma predeterminada para este dispositivo USB"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Usar de forma predeterminada para este accesorio USB"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Abrir siempre <xliff:g id="APPLICATION">%1$s</xliff:g> al conectar <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Abrir siempre <xliff:g id="APPLICATION">%1$s</xliff:g> al conectar <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"¿Permitir depuración por USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"La huella digital de tu clave RSA es:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Permitir siempre desde este ordenador"</string>
@@ -245,8 +245,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datos pausados"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Se ha alcanzado el límite de datos establecido. Ya no estás utilizando datos móviles.\n\nSi vuelves a activar el uso de datos, es posible que se apliquen cargos."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reanudar"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Con conexión Wi-Fi"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando señal GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Ubicación definida por GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Solicitudes de ubicación activas"</string>
@@ -403,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"¿Quitar usuario?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Se eliminarán todas las aplicaciones y todos los datos de este usuario."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Quitar"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Ahorro de batería activado"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Ahorro de batería activado"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce el rendimiento y los datos en segundo plano"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactivar ahorro de batería"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Desactivar Ahorro de batería"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> empezará a capturar todo lo que aparezca en la pantalla."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"No volver a mostrar"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Borrar todo"</string>
@@ -584,8 +582,8 @@
<item quantity="one">%d minuto</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Uso de la batería"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"La función Ahorro de batería no está disponible mientras se carga el dispositivo"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Ahorro de batería"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ahorro de batería no disponible mientras se carga el dispositivo"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Ahorro de batería"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce el rendimiento y los datos en segundo plano"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Inicio"</string>
diff --git a/packages/SystemUI/res/values-et/config.xml b/packages/SystemUI/res/values-et/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-et/config.xml
+++ b/packages/SystemUI/res/values-et/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 2b37558..3a4eea6 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Märguanded"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Aku hakkab tühjaks saama"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Jäänud on <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Jäänud on <xliff:g id="PERCENTAGE">%s</xliff:g>. Akusäästja on sisse lülitatud."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Jäänud on <xliff:g id="PERCENTAGE">%s</xliff:g>. Akusäästja on sisse lülitatud."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB laadimist ei toetata.\nKasutage ainult tootja laadija."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB-ga laadimist ei toetata."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Kasutage ainult kaasasolevat laadijat."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Seaded"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Kas lülitada sisse akusäästja?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Kas lülitada akusäästja sisse?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Lülita sisse"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Akusäästja sisselülitamine"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Akusäästja sisselülitamine"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Seaded"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WiFi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Pööra ekraani automaatselt"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth on jagatud"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Seadista sisestusmeetodeid"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Füüsiline klaviatuur"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Kas lubate rakendusel <xliff:g id="APPLICATION">%1$s</xliff:g> USB-seadmele juurde pääseda?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Kas lubate rakendusel <xliff:g id="APPLICATION">%1$s</xliff:g> USB-seadmele juurde pääseda?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Kas avada <xliff:g id="ACTIVITY">%1$s</xliff:g>, kui see USB-seade on ühendatud?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Kas avada <xliff:g id="ACTIVITY">%1$s</xliff:g>, kui USB-lisaseade on ühendatud?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Kas lubada rakendusele <xliff:g id="APPLICATION">%1$s</xliff:g> juurdepääs seadmele <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Kas lubada rakendusele <xliff:g id="APPLICATION">%1$s</xliff:g> juurdepääs seadmele <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Kas avada rakendus <xliff:g id="APPLICATION">%1$s</xliff:g> seadme <xliff:g id="USB_DEVICE">%2$s</xliff:g> kasutamiseks?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Kas avada rakendus <xliff:g id="APPLICATION">%1$s</xliff:g> seadme <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> kasutamiseks?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Inst. rak. ei tööta selle USB-seadmega. Lisateavet lisaseadme kohta vt siit: <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB-lisaseade"</string>
<string name="label_view" msgid="6304565553218192990">"Kuva"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Kasuta vaikimisi selle USB-seadme jaoks"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Vaikimisi kasuta seda USB-lisaseadet"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Ava rakendus <xliff:g id="APPLICATION">%1$s</xliff:g> alati, kui seade <xliff:g id="USB_DEVICE">%2$s</xliff:g> on ühendatud"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Ava rakendus <xliff:g id="APPLICATION">%1$s</xliff:g> alati, kui seade <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> on ühendatud"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Kas luban USB silumise?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Arvuti RSA-võtme sõrmejälg:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Luba alati sellest arvutist"</string>
@@ -245,8 +245,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Andmekasutus on peatatud"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Olete jõudnud määratud andmemahupiiranguni. Te ei kasuta enam mobiilset andmesidet.\n\nJätkamisel võib andmekasutus olla tasuline."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jätka"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Interneti-ühendus puudub"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WiFi on ühendatud"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS-i otsimine"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS-i määratud asukoht"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Asukoha taotlused on aktiivsed"</string>
@@ -403,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Kas eemaldada kasutaja?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Kasutaja kõik rakendused ja andmed kustutatakse."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Eemalda"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Akusäästja on sisse lülitatud"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Akusäästja on sisse lülitatud"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Vähendab jõudlust ja taustaandmeid"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Akusäästja väljalülitamine"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Akusäästja väljalülitamine"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> hakkab jäädvustama kõike, mida ekraanil kuvatakse."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ära kuva uuesti"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Tühjenda kõik"</string>
@@ -584,8 +582,8 @@
<item quantity="one">%d minut</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Akukasutus"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Akusäästja pole laadimise ajal saadaval"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Akusäästja"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Akusäästja pole laadimise ajal saadaval"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Akusäästja"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Vähendab jõudlust ja taustaandmeid"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Nupp <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Avaekraan"</string>
diff --git a/packages/SystemUI/res/values-eu/config.xml b/packages/SystemUI/res/values-eu/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-eu/config.xml
+++ b/packages/SystemUI/res/values-eu/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index a7b5938..b75548e5 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Jakinarazpenak"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Bateria agortzen ari da"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> gelditzen da"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> gelditzen da. Bateria-aurrezteko aukera aktibatuta dago."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> gelditzen da. Bateria-aurrezlea aktibatuta dago."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Ez da USB bidez kargatzea onartzen.\nErabili hornitu zaizun kargagailua soilik."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Ez da USB bidez kargatzea onartzen."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Erabili jatorrizko kargagailua soilik."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Ezarpenak"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Bateria aurrezteko aukera aktibatu nahi duzu?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Bateria-aurrezlea aktibatu nahi duzu?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Aktibatu"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Aktibatu bateria aurrezteko aukera"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Aktibatu bateria-aurrezlea"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ezarpenak"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Biratu pantaila automatikoki"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetootha konektatu da"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfiguratu idazketa-metodoak"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Teklatu fisikoa"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioari USB gailua atzitzeko baimena eman nahi diozu?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioari USB osagarria atzitzeko baimena eman nahi diozu?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"USB gailu hau konektatuta dagoenean <xliff:g id="ACTIVITY">%1$s</xliff:g> ireki nahi duzu?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"USB osagarri hau konektatuta dagoenean <xliff:g id="ACTIVITY">%1$s</xliff:g> ireki nahi duzu?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> atzitzeko baimena eman nahi diozu <xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioari?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> atzitzeko baimena eman nahi diozu <xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioari?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="APPLICATION">%1$s</xliff:g> ireki nahi duzu <xliff:g id="USB_DEVICE">%2$s</xliff:g> kudeatzeko?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="APPLICATION">%1$s</xliff:g> ireki nahi duzu <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> kudeatzeko?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Instalatutako aplikazioek ez dute USB osagarri honekin funtzionatzen. Lortu informazio gehiago osagarriari buruz hemen: <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB osagarria"</string>
<string name="label_view" msgid="6304565553218192990">"Ikusi"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Erabili lehenetsi gisa USB gailu honetarako"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Erabili modu lehenetsian USB osagarri honetarako"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Ireki <xliff:g id="APPLICATION">%1$s</xliff:g> <xliff:g id="USB_DEVICE">%2$s</xliff:g> konektatzen den guztietan"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Ireki <xliff:g id="APPLICATION">%1$s</xliff:g> <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> konektatzen den guztietan"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB arazketa onartu?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Ordenagailuaren RSA gakoaren hatz-marka hau da:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Onartu beti ordenagailu honetatik"</string>
@@ -245,8 +245,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datuen erabilera eten da"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Iritsi zara ezarri zenuen datu-mugara. Datu mugikorrak erabiltzeari utzi diozu.\n\nDatu mugikorrak erabiltzeari berrekiten badiozu, datuen erabileragatiko gastuak izango dituzu."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jarraitu erabiltzen"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ez duzu Interneteko konexiorik"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi konektatuta"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS seinalearen bila"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Kokapena GPS bidez ezarri da"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Aplikazioen kokapen-eskaerak aktibo daude"</string>
@@ -403,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Erabiltzailea kendu nahi duzu?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Erabiltzailearen aplikazio eta datu guztiak ezabatuko dira."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Kendu"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Bateria-aurrezlea aktibatuta dago"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Aktibatuta dago bateria-aurrezlea"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Errendimendua eta atzeko planoko datuak murrizten ditu"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desaktibatu bateria aurrezteko aukera"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Desaktibatu bateria-aurrezlea"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioak pantailan bistaratzen den guztia grabatuko du."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ez erakutsi berriro"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Garbitu guztiak"</string>
@@ -584,8 +582,8 @@
<item quantity="one">%d minutu</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Bateriaren erabilera"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Bateria-aurrezlea ez dago erabilgarri gailua kargatzen ari denean"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Bateria-aurrezlea"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Bateria-aurrezlea ez dago erabilgarri gailua kargatzen ari denean"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Bateria-aurrezlea"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Errendimendua eta atzeko planoko datuen erabilera murrizten ditu"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> botoia"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Hasiera"</string>
diff --git a/packages/SystemUI/res/values-fa/config.xml b/packages/SystemUI/res/values-fa/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-fa/config.xml
+++ b/packages/SystemUI/res/values-fa/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 64e34a9..d107fea 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"اعلانها"</string>
<string name="battery_low_title" msgid="6456385927409742437">"شارژ باتری کم است"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی مانده است"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی مانده است. بهینهسازی باتری روشن است."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی مانده است. بهینهسازی باتری روشن است."</string>
<string name="invalid_charger" msgid="4549105996740522523">"شارژ USB پشتیبانی نمیشود.\nفقط از شارژر ارائه شده استفاده کنید."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"شارژ با USB پشتیبانی نمیشود."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"فقط از شارژر ارائه شده استفاده کنید."</string>
<string name="battery_low_why" msgid="4553600287639198111">"تنظیمات"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"بهینهسازی باتری روشن شود؟"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"بهینهسازی باتری روشن شود؟"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"روشن کردن"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"بهینهسازی باتری را روشن کنید"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"بهینهسازی باتری را روشن کنید"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"تنظیمات"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"چرخش خودکار صفحه"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"اتصال اینترنتی با بلوتوث تلفن همراه"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"تنظیم روشهای ورودی"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"صفحهکلید فیزیکی"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"به برنامه <xliff:g id="APPLICATION">%1$s</xliff:g> اجازه میدهید به دستگاه USB دسترسی داشته باشد؟"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"به برنامه <xliff:g id="APPLICATION">%1$s</xliff:g> اجازه میدهد تا به وسیله جانبی USB دسترسی داشته باشد؟"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"وقتی این دستگاه USB وصل است، <xliff:g id="ACTIVITY">%1$s</xliff:g> باز شود؟"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"وقتی این وسیله جانبی USB وصل است، <xliff:g id="ACTIVITY">%1$s</xliff:g> باز شود؟"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"به <xliff:g id="APPLICATION">%1$s</xliff:g> برای دسترسی به <xliff:g id="USB_DEVICE">%2$s</xliff:g> اجازه داده شود؟"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"به <xliff:g id="APPLICATION">%1$s</xliff:g> برای دسترسی به <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> اجازه داده شود؟"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"برای استفاده از <xliff:g id="USB_DEVICE">%2$s</xliff:g>، <xliff:g id="APPLICATION">%1$s</xliff:g> باز شود؟"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"برای استفاده از <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>، <xliff:g id="APPLICATION">%1$s</xliff:g> باز شود؟"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"هیچ برنامه نصب شدهای با این وسیله جانبی USB کار نمیکند. در <xliff:g id="URL">%1$s</xliff:g> دربارهٔ این وسیله جانبی اطلاعات بیشتری کسب کنید"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"لوازم جانبی USB"</string>
<string name="label_view" msgid="6304565553218192990">"مشاهده"</string>
- <string name="always_use_device" msgid="1450287437017315906">"استفاده به صورت پیشفرض برای این دستگاه USB"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"استفاده به صورت پیشفرض برای این دستگاه USB"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"همیشه هنگام اتصال <xliff:g id="USB_DEVICE">%2$s</xliff:g>، <xliff:g id="APPLICATION">%1$s</xliff:g> باز شود"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"همیشه هنگام اتصال <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>، <xliff:g id="APPLICATION">%1$s</xliff:g> باز شود"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"اشکالزدایی USB مجاز است؟"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"اثر انگشت کلید RSA رایانه: \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"همیشه از این رایانه انجام شود"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"داده موقتاً متوقف شده است"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"مصرف داده شما به محدودیت دادهای که تنظیم کردید رسیده است. دیگر از داده تلفن همراه استفاده نمیکنید.\n\n درصورت ازسرگیری، ممکن است هزینههای مصرف داده اعمال شود."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"از سرگیری"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"اتصال اینترنتی ندارید"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi متصل شد"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"جستجو برای GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"مکان تنظیم شده توسط GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"درخواستهای موقعیت مکانی فعال است"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"کاربر حذف شود؟"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"همه برنامهها و دادههای این کاربر حذف میشود."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"حذف"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"بهینهسازی باتری روشن است."</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"بهینهسازی باتری روشن است"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"عملکرد و اطلاعات پسزمینه را کاهش میدهد"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"بهینهسازی باتری را خاموش کنید"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"بهینهسازی باتری را خاموش کنید"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> شروع به ضبط هر چیزی میکند که در صفحهنمایش شما نمایش داده میشود."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"دوباره نشان داده نشود"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"پاک کردن همه موارد"</string>
@@ -582,8 +580,8 @@
<item quantity="other">%d دقیقه</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"مصرف باتری"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"«بهینهسازی باتری» در هنگام شارژ شدن در دسترس نیست"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"بهینهسازی باتری"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"هنگام شارژ شدن، «بهینهسازی باتری» در دسترس نیست"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"بهینهسازی باتری"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"عملکرد و اطلاعات پسزمینه را کاهش میدهد"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"دکمه <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"ابتدا"</string>
@@ -758,7 +756,8 @@
<string name="instant_apps" msgid="6647570248119804907">"برنامههای فوری"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"برنامههای فوری نیاز به نصب ندارند."</string>
<string name="app_info" msgid="6856026610594615344">"اطلاعات برنامه"</string>
- <string name="go_to_web" msgid="1106022723459948514">"رفتن به وب"</string>
+ <!-- no translation found for go_to_web (2650669128861626071) -->
+ <skip />
<string name="mobile_data" msgid="7094582042819250762">"داده تلفن همراه"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi خاموش است"</string>
<string name="bt_is_off" msgid="2640685272289706392">"بلوتوث خاموش است"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 65d80a9..ccec4a6 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ilmoitukset"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Akku on vähissä"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> jäljellä"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> jäljellä. Virransäästö on käytössä."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> jäljellä. Virransäästö on käytössä."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-latausta ei tueta.\nKäytä laitteen mukana tullutta laturia."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB-latausta ei tueta."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Käytä vain laitteen mukana toimitettua laturia."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Asetukset"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Otetaanko virransäästö käyttöön?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Otetaanko virransäästö käyttöön?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Ota käyttöön"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Ota virransäästö käyttöön"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Ota virransäästö käyttöön"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Asetukset"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Näytön automaattinen kierto"</string>
@@ -51,21 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth yhdistetty"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Määritä syöttötavat"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fyysinen näppäimistö"</string>
- <!-- no translation found for usb_device_permission_prompt (1825685909587559679) -->
- <skip />
- <!-- no translation found for usb_accessory_permission_prompt (2465531696941369047) -->
- <skip />
- <!-- no translation found for usb_device_confirm_prompt (7440562274256843905) -->
- <skip />
- <!-- no translation found for usb_accessory_confirm_prompt (4333670517539993561) -->
- <skip />
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Saako <xliff:g id="APPLICATION">%1$s</xliff:g> käyttöoikeuden (<xliff:g id="USB_DEVICE">%2$s</xliff:g>)?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Saako <xliff:g id="APPLICATION">%1$s</xliff:g> käyttöoikeuden (<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>)?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Avataanko <xliff:g id="APPLICATION">%1$s</xliff:g>, jotta <xliff:g id="USB_DEVICE">%2$s</xliff:g> voidaan ottaa käyttöön?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Avataanko <xliff:g id="APPLICATION">%1$s</xliff:g>, jotta <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> voidaan ottaa käyttöön?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Asennetut sov. eivät toimi tämän USB-laitteen kanssa. Lisätietoja laitteesta: <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB-lisälaite"</string>
<string name="label_view" msgid="6304565553218192990">"Näytä"</string>
- <!-- no translation found for always_use_device (4015357883336738417) -->
- <skip />
- <!-- no translation found for always_use_accessory (3257892669444535154) -->
- <skip />
+ <string name="always_use_device" msgid="4015357883336738417">"Avaa <xliff:g id="APPLICATION">%1$s</xliff:g> aina, kun <xliff:g id="USB_DEVICE">%2$s</xliff:g> liitetään"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Avaa <xliff:g id="APPLICATION">%1$s</xliff:g> aina, kun <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> liitetään"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Sallitaanko USB-vianetsintä?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Tietokoneen RSA-avaintunnistetiedosto on:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Salli aina tällä tietokoneella"</string>
@@ -249,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Tiedonsiirto keskeytettiin"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Asettamasi dataraja on saavutettu. Et enää käytä mobiilidataa.\n\nJos jatkat käyttöä, datan käytöstä saatetaan periä maksuja."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jatka"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ei internetyhteyttä"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi yhdistetty"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Haetaan GPS-yhteyttä"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Sijainti määritetty GPS:n avulla"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Sijaintipyynnöt aktiiviset"</string>
@@ -407,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Poistetaanko käyttäjä?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Kaikki käyttäjän tiedot ja sovellukset poistetaan."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Poista"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Virransäästö on käytössä"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Virransäästö on käytössä"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Rajoittaa suorituskykyä ja taustatiedonsiirtoa"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Poista virransäästö käytöstä"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Poista virransäästö käytöstä"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> alkaa tallentaa kaiken näytölläsi näkyvän."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Älä näytä uudelleen"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Poista kaikki"</string>
@@ -588,8 +580,8 @@
<item quantity="one">%d minuutti</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Akun käyttö"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Virransäästö ei ole käytettävissä latauksen aikana."</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Virransäästö"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Virransäästö ei ole käytettävissä latauksen aikana."</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Virransäästö"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Rajoittaa suorituskykyä ja taustatiedonsiirtoa."</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Painike <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 6e1feea..bdd01c2 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Pile faible"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> restants"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> restants. L\'économiseur d\'énergie est activé."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> restants. La fonction Économie d\'énergie est activée."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Chargement USB non compatible.\nVous devez utiliser le chargeur fourni."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Le chargement par USB n\'est pas pris en charge."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Utilisez uniquement le chargeur fourni."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Paramètres"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Activer l\'économiseur d\'énergie?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Activer la fonction Économie d\'énergie?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Activer"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Activer l\'économiseur d\'énergie"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Activer la fonction Économie d\'énergie"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Paramètres"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rotation auto de l\'écran"</string>
@@ -245,8 +245,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Données désactivées"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"La limite de données que vous avez définie a été atteinte. Vous n\'utilisez plus les données cellulaires.\n\nSi vous rétablissez la connexion de données cellulaires, des frais peuvent s\'appliquer."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reprendre"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Recherche de GPS..."</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Position définie par GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Demandes de localisation actives"</string>
@@ -403,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Supprimer l\'utilisateur?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Toutes les applications et les données de cet utilisateur seront supprimées."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Supprimer"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"La fonction Économie d\'énergie est activée"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"La fonction Économie d\'énergie est activée"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Réduire les performances et de fond"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Désactiver l\'économiseur d\'énergie"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Désactiver la fonction Économie d\'énergie"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> commencer à enregistrer tout ce qui s\'affiche sur votre écran."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ne plus afficher"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Tout effacer"</string>
@@ -584,8 +582,8 @@
<item quantity="other">%d minutes</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Utilisation de la pile"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Le mode Économie d\'énergie n\'est pas accessible pendant la recharge"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Économie d\'énergie"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Le mode Économie d\'énergie n\'est pas accessible pendant la charge"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Économie d\'énergie"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Réduit les performances et les données en arrière-plan"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Bouton <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Accueil"</string>
diff --git a/packages/SystemUI/res/values-fr/config.xml b/packages/SystemUI/res/values-fr/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-fr/config.xml
+++ b/packages/SystemUI/res/values-fr/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 4b4e5b7..ee50e56 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Batterie faible"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> restants"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> restants. L\'économiseur de batterie est activé."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> restants. L\'économiseur de batterie est activé."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Chargement USB non disponible.\nVous devez utiliser le chargeur fourni."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Chargeur USB non compatible."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Veuillez n\'utiliser que le chargeur fourni."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Paramètres"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Activer l\'économiseur de batterie ?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Activer l\'économiseur de batterie ?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Activer"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Activer l\'économiseur de batterie"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Activer l\'économiseur de batterie ?"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Paramètres"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rotation automatique de l\'écran"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Connexion Bluetooth partagée"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configurer les modes de saisie"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Clavier physique"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Autoriser l\'application <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder au périphérique USB ?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Autoriser l\'application <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder à l\'accessoire USB ?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Ouvrir <xliff:g id="ACTIVITY">%1$s</xliff:g> lors de la connexion de ce périphérique USB ?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Ouvrir <xliff:g id="ACTIVITY">%1$s</xliff:g> lors de la connexion de cet accessoire USB ?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Autoriser <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder à <xliff:g id="USB_DEVICE">%2$s</xliff:g> ?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Autoriser <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder à <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Ouvrir <xliff:g id="APPLICATION">%1$s</xliff:g> pour utiliser <xliff:g id="USB_DEVICE">%2$s</xliff:g> ?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Ouvrir <xliff:g id="APPLICATION">%1$s</xliff:g> pour utiliser <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Aucune application installée compatible avec accessoire USB. En savoir plus sur <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Accessoire USB"</string>
<string name="label_view" msgid="6304565553218192990">"Afficher"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Utiliser par défaut pour ce périphérique USB"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Utiliser par défaut pour cet accessoire USB"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Toujours ouvrir <xliff:g id="APPLICATION">%1$s</xliff:g> quand <xliff:g id="USB_DEVICE">%2$s</xliff:g> est connecté"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Toujours ouvrir <xliff:g id="APPLICATION">%1$s</xliff:g> quand <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> est connecté"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Autoriser le débogage USB ?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Empreinte numérique de la clé RSA de l\'ordinateur : \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Toujours autoriser sur cet ordinateur"</string>
@@ -245,8 +245,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Données désactivées"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Vous avez atteint la limite de données que vous aviez définie. Vous n\'utilisez plus de données mobiles.\n\nSi vous réactivez les données, des frais peuvent s\'appliquer."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Réactiver"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Recherche de GPS..."</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Position définie par GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Demandes de localisation actives"</string>
@@ -403,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Supprimer l\'utilisateur ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Toutes les applications et les données de cet utilisateur seront supprimées."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Supprimer"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"L\'économiseur de batterie est activé"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Économiseur de batterie activé"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Limite les performances et les données en arrière-plan."</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Désactiver l\'économiseur de batterie"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Désactiver l\'économiseur de batterie"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> va commencer à capturer tous les contenus affichés à l\'écran."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ne plus afficher"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Tout effacer"</string>
@@ -584,8 +582,8 @@
<item quantity="other">%d minutes</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Utilisation batterie"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"L\'économiseur de batterie n\'est pas disponible lorsque l\'appareil est en charge"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Économiseur de batterie"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"L\'économiseur de batterie n\'est pas disponible lorsque l\'appareil est en charge."</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Économiseur de batterie"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Limite les performances et les données en arrière-plan."</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Bouton <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Accueil"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 94c525a..558b98c 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificacións"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Queda pouca batería"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante. A función de aforro da batería está activada."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante. Está activada a función Aforro de batería."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Non compatible coa carga por USB.\nUtiliza só o cargador proporcionado."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Non se admite a carga mediante USB."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Utiliza soamente o cargador fornecido."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Configuración"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Queres activar o aforro de batería?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Queres activar a función Aforro de batería?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Activar"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Activar o aforro de batería"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Activar a función Aforro de batería"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configuración"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wifi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Xirar pantalla automaticamente"</string>
@@ -51,21 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Conexión compartida por Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configurar métodos de entrada"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Teclado físico"</string>
- <!-- no translation found for usb_device_permission_prompt (1825685909587559679) -->
- <skip />
- <!-- no translation found for usb_accessory_permission_prompt (2465531696941369047) -->
- <skip />
- <!-- no translation found for usb_device_confirm_prompt (7440562274256843905) -->
- <skip />
- <!-- no translation found for usb_accessory_confirm_prompt (4333670517539993561) -->
- <skip />
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Queres permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Queres permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Queres abrir <xliff:g id="APPLICATION">%1$s</xliff:g> para utilizar <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Queres abrir <xliff:g id="APPLICATION">%1$s</xliff:g> para utilizar <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Ningunha aplicación instalada funciona co accesorio USB. Máis información: <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Accesorio USB"</string>
<string name="label_view" msgid="6304565553218192990">"Ver"</string>
- <!-- no translation found for always_use_device (4015357883336738417) -->
- <skip />
- <!-- no translation found for always_use_accessory (3257892669444535154) -->
- <skip />
+ <string name="always_use_device" msgid="4015357883336738417">"Abrir sempre <xliff:g id="APPLICATION">%1$s</xliff:g> cando se conecte <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Abrir sempre <xliff:g id="APPLICATION">%1$s</xliff:g> cando se conecte <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Permitir a depuración de erros de USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"A impresión dixital da clave de RSA do ordenador é:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Permitir sempre desde este ordenador"</string>
@@ -251,8 +245,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os datos están en pausa"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Alcanzouse o límite de datos que fixaches. Xa non estás usando datos móbiles.\n\nSe os reactivas, pódense aplicar cargos polo seu uso."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sen Internet"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectada"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Localización establecida polo GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Solicitudes de localización activas"</string>
@@ -409,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Queres eliminar o usuario?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Eliminaranse todas as aplicacións e os datos deste usuario."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Eliminar"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"O aforro de batería está activado"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"A función Aforro de batería está activada"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce o rendemento e os datos en segundo plano"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactivar o aforro de batería"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Desactivar a función Aforro de batería"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> comezará a capturar todo o que apareza na túa pantalla."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Non mostrar outra vez"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Eliminar todas"</string>
@@ -590,8 +582,8 @@
<item quantity="one">%d minuto</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Uso de batería"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"A función Aforro de batería non está dispoñible durante a carga"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Aforro de batería"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"A función de aforro da batería non está dispoñible durante a carga"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Aforro de batería"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce o rendemento e os datos en segundo plano"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Inicio"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index b13011a..139ab82 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -34,14 +34,17 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"નોટિફિકેશનો"</string>
<string name="battery_low_title" msgid="6456385927409742437">"બૅટરી ઓછી છે"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> બાકી"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> બાકી. બૅટરી સેવર ચાલુ છે."</string>
+ <!-- no translation found for battery_low_percent_format_saver_started (7879389868952879166) -->
+ <skip />
<string name="invalid_charger" msgid="4549105996740522523">"USB ચાર્જિંગ સમર્થિત નથી.\nફક્ત આપવામાં આવેલ ચાર્જરનો ઉપયોગ કરો."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB ચાર્જિંગ સમર્થિત નથી."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"ફક્ત પ્રદાન કરાયેલ ચાર્જરનો ઉપયોગ કરો."</string>
<string name="battery_low_why" msgid="4553600287639198111">"સેટિંગ્સ"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"બૅટરી સેવર ચાલુ કરીએ?"</string>
+ <!-- no translation found for battery_saver_confirmation_title (2052100465684817154) -->
+ <skip />
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"ચાલુ કરો"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"બૅટરી સેવર ચાલુ કરો"</string>
+ <!-- no translation found for battery_saver_start_action (8187820911065797519) -->
+ <skip />
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"સેટિંગ્સ"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"વાઇ-ફાઇ"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"સ્ક્રીનને આપમેળે ફેરવો"</string>
@@ -51,21 +54,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"બ્લૂટૂથ ટિથર કર્યું"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ઇનપુટ પદ્ધતિઓ સેટ કરો"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"ભૌતિક કીબોર્ડ"</string>
- <!-- no translation found for usb_device_permission_prompt (1825685909587559679) -->
- <skip />
- <!-- no translation found for usb_accessory_permission_prompt (2465531696941369047) -->
- <skip />
- <!-- no translation found for usb_device_confirm_prompt (7440562274256843905) -->
- <skip />
- <!-- no translation found for usb_accessory_confirm_prompt (4333670517539993561) -->
- <skip />
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ના ઍક્સેસ માટે <xliff:g id="APPLICATION">%1$s</xliff:g>ને મંજૂરી આપીએ?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>ના ઍક્સેસ માટે <xliff:g id="APPLICATION">%1$s</xliff:g>ને મંજૂરી આપીએ?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ને હૅન્ડલ કરવા માટે <xliff:g id="APPLICATION">%1$s</xliff:g>ને ખોલીએ?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>ને હૅન્ડલ કરવા માટે <xliff:g id="APPLICATION">%1$s</xliff:g>ને ખોલીએ?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"કોઈપણ ઇન્સ્ટોલ કરેલી ઍપ્લિકેશનો આ USB ઍક્સેસરી સાથે કામ કરતી નથી. આ ઍક્સેસરી વિશે <xliff:g id="URL">%1$s</xliff:g> પર વધુ જાણો."</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB ઍક્સેસરી"</string>
<string name="label_view" msgid="6304565553218192990">"જુઓ"</string>
- <!-- no translation found for always_use_device (4015357883336738417) -->
- <skip />
- <!-- no translation found for always_use_accessory (3257892669444535154) -->
- <skip />
+ <string name="always_use_device" msgid="4015357883336738417">"જ્યારે <xliff:g id="USB_DEVICE">%2$s</xliff:g> કનેક્ટેડ હોય ત્યારે <xliff:g id="APPLICATION">%1$s</xliff:g>ને હંમેશા ખોલો"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"જ્યારે <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> કનેક્ટેડ હોય ત્યારે <xliff:g id="APPLICATION">%1$s</xliff:g>ને હંમેશા ખોલો"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB ડિબગિંગને મંજૂરી આપીએ?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"કમ્પ્યુટરની RSA મુખ્ય ફિંગરપ્રિંટ આ છે:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"હંમેશા આ કમ્પ્યુટરથી મંજૂરી આપો"</string>
@@ -249,8 +246,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ડેટા થોભાવ્યો છે"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"તમારા દ્વારા સેટ કરેલ ડેટા મર્યાદા પર તમે પહોંચી ગયાં છો. તમે હવે મોબાઇલ ડેટાનો ઉપયોગ કરી રહ્યાં નથી.\n\nજો તમે ફરી શરૂ કરો છો, તો ડેટા વપરાશ માટે શુલ્ક લાગુ થઈ શકે છે."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ફરી શરૂ કરો"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"કોઈ ઇન્ટરનેટ કનેક્શન નથી"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"વાઇ-ફાઇ કનેક્ટ કર્યું"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS માટે શોધી રહ્યાં છે"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS દ્વારા સ્થાન સેટ કરાયું"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"સ્થાન વિનંતીઓ સક્રિય"</string>
@@ -407,9 +402,11 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"વપરાશકર્તાને દૂર કરીએ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"આ વપરાશકર્તાની તમામ ઍપ્લિકેશનો અને ડેટા કાઢી નાખવામાં આવશે."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"દૂર કરો"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"બેટરી સેવર ચાલુ છે"</string>
+ <!-- no translation found for battery_saver_notification_title (8614079794522291840) -->
+ <skip />
<string name="battery_saver_notification_text" msgid="820318788126672692">"પ્રદર્શન અને બૅકગ્રાઉન્ડ ડેટા ઘટાડે છે"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"બૅટરી સેવર બંધ કરો"</string>
+ <!-- no translation found for battery_saver_notification_action_text (132118784269455533) -->
+ <skip />
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> તમારી સ્ક્રીન પર જે પ્રદર્શિત થાય છે તે દરેક વસ્તુને કેપ્ચર કરવાનું પ્રારંભ કરશે."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"ફરીથી બતાવશો નહીં"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"બધુ સાફ કરો"</string>
@@ -588,8 +585,8 @@
<item quantity="other">%d મિનિટ</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"બૅટરી વપરાશ"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"ચાર્જિંગ દરમિયાન બૅટરી સેવર ઉપલબ્ધ હોતું નથી"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"બૅટરી સેવર"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ચાર્જિંગ દરમિયાન બૅટરી સેવર ઉપલબ્ધ નથી"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"બૅટરી સેવર"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"પ્રદર્શન અને બૅકગ્રાઉન્ડ ડેટા ઘટાડે છે"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"બટન <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index dd1f729..1681c2e 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"सूचनाएं"</string>
<string name="battery_low_title" msgid="6456385927409742437">"बैटरी कम है"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> शेष"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> शेष. बैटरी सेवर चालू है."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> बैटरी बची है. बैटरी सेवर चालू है."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB चार्जिंग समर्थित नहीं है.\nकेवल आपूर्ति किए गए चार्जर का उपयोग करें."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB चार्जिंग समर्थित नहीं है."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"केवल आपूर्ति किए गए चार्जर का उपयोग करें."</string>
<string name="battery_low_why" msgid="4553600287639198111">"सेटिंग"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"बैटरी बचतकर्ता चालू करें?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"क्या आप बैटरी सेवर चालू करना चाहते हैं?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"चालू करें"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"बैटरी बचाएँ"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"बैटरी सेवर चालू करें"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"सेटिंग"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"वाई-फ़ाई"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"स्क्रीन अपने आप घुमाएं"</string>
@@ -50,7 +50,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"सूचनाएं"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"ब्लूटूथ टीदर किया गया"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"इनपुट का तरीका सेट करें"</string>
- <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"भौतिक कीबोर्ड"</string>
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"सामान्य कीबोर्ड"</string>
<string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> को <xliff:g id="USB_DEVICE">%2$s</xliff:g> के एक्सेस की अनुमति दें?"</string>
<string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> को <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> के एक्सेस की अनुमति दें?"</string>
<string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> के लिए <xliff:g id="APPLICATION">%1$s</xliff:g> खोलें?"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटा रोक दिया गया है"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"आपकी सेट की हुई डेटा सीमा खत्म हो गई है. अब आप मोबाइल डेटा का इस्तेमाल नहीं कर रहे हैं.\n\nअगर आप फिर से शुरू करते हैं, तो डेटा खर्च के लिए शुल्क लागू किया जा सकता है."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"फिर से शुरू करें"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"कोई इंटरनेट कनेक्शन नहीं"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाई-फ़ाई कनेक्ट किया गया"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS को खोजा जा रहा है"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"जीपीएस ने यह जगह सेट की है"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"जगह का अनुरोध किया जा रहा है"</string>
@@ -333,7 +331,7 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"स्क्रीन पिन करना"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"सर्च"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> प्रारंभ नहीं किया जा सका."</string>
- <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> को सुरक्षित-मोड में अक्षम किया गया."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> को सुरक्षित-मोड में बंद किया गया."</string>
<string name="recents_stack_action_button_label" msgid="6593727103310426253">"Clear all"</string>
<string name="recents_drag_hint_message" msgid="2649739267073203985">"स्क्रीन के दो हिस्से में बंट जाने, स्पिल्ट स्क्रीन, का इस्तेमाल करने के लिए यहां खींचें और छोडें"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"क्षैतिज रूप से विभाजित करें"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"उपयोगकर्ता निकालें?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"इस उपयोगकर्ता के सभी ऐप और डेटा को हटा दिया जाएगा."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"निकालें"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"बैटरी सेवर चालू है"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"बैटरी सेवर चालू है"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"निष्पादन और पृष्ठभूमि डेटा को कम करता है"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"बैटरी बचतकर्ता को बंद करें"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"बैटरी सेवर बंद करें"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> आपके स्क्रीन पर दिखाई देने वाली हर सामग्री को कैप्चर करना शुरू कर देगी."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"फिर से न दिखाएं"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"सभी साफ़ करें"</string>
@@ -582,8 +580,8 @@
<item quantity="other">%d मिनट</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"बैटरी उपयोग"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"चार्ज करते समय बैटरी सेवर उपलब्ध नहीं होता"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"बैटरी सेवर"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"चार्ज किए जाने के दौरान बैटरी सेवर उपलब्ध नहीं है"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"बैटरी सेवर"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"निष्पादन और पृष्ठभूमि डेटा को कम करता है"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"बटन <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-hr/config.xml b/packages/SystemUI/res/values-hr/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-hr/config.xml
+++ b/packages/SystemUI/res/values-hr/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 43aa345..699efad 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -35,14 +35,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Obavijesti"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Niska razina baterije"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Preostalo <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Preostalo <xliff:g id="PERCENTAGE">%s</xliff:g>. Uključena je štednja baterije."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Preostalo <xliff:g id="PERCENTAGE">%s</xliff:g>. Uključena je Štednja baterije."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB punjenje nije podržano.\nUpotrijebite samo priloženi punjač."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Punjenje putem USB-a nije podržano."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Upotrebljavajte samo priloženi punjač."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Postavke"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Želite li uključiti uštedu baterije?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Želite li uključiti Štednju baterije?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Uključi"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Uključi uštedu baterije"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Uključite Štednju baterije"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Postavke"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatski zakreni zaslon"</string>
@@ -52,15 +52,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth posredno povezan"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Postavljanje načina unosa"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fizička tipkovnica"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Dopustiti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> da pristupi ovom USB uređaju?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Dopustiti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> da pristupi ovom USB dodatku?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Otvoriti <xliff:g id="ACTIVITY">%1$s</xliff:g> kad se spoji ovaj USB uređaj?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Otvoriti <xliff:g id="ACTIVITY">%1$s</xliff:g> kad se spoji ovaj USB dodatak?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Želite li dopustiti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> pristup uređaju <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Želite li dopustiti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> pristup uređaju <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Želite li otvoriti aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g> radi upravljanja uređajem <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Želite li otvoriti aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g> radi upravljanja uređajem <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Nijedna instalirana aplikacija ne radi s ovim USB dodatkom. Saznajte više na <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB pribor"</string>
<string name="label_view" msgid="6304565553218192990">"Prikaži"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Koristi se prema zadanim postavkama za ovaj USB uređaj"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Koristi se prema zadanim postavkama za ovaj USB pribor"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Uvijek otvori aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g> kada se poveže uređaj <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Uvijek otvori aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g> kada se poveže uređaj <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Omogućiti otklanjanje pogrešaka putem USB-a?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Otisak prsta RSA ključa računala je: \n <xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Uvijek dopusti s ovog računala"</string>
@@ -244,8 +244,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Podaci su pauzirani"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Dostigli ste postavljeno ograničenje za podatkovni promet. Više ne upotrebljavate mobilni podatkovni promet.\n\nAko nastavite, moguća je naplata za potrošeni podatkovni promet."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internetske veze"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Traženje GPS-a"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokaciju utvrdio GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Zahtjevi za lokaciju aktivni su"</string>
@@ -403,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Ukloniti korisnika?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Izbrisat će se sve aplikacije i podaci ovog korisnika."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Ukloni"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Štednja baterije je uključena"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Štednja baterije je uključena"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Smanjuje količinu rada i pozadinske podatke"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Isključi uštedu baterije"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Isključite Štednju baterije"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> počet će snimati sve što se prikazuje na zaslonu."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ne prikazuj ponovo"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Izbriši sve"</string>
@@ -588,8 +586,8 @@
<item quantity="other">%d minuta</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Potrošnja baterije"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Štednja baterije nije dostupna tijekom punjenja"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Štednja baterije"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Štednja baterije nije dostupna tijekom punjenja"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Štednja baterije"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Smanjuje količinu rada i pozadinske podatke"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Tipka <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Početak"</string>
diff --git a/packages/SystemUI/res/values-hu/config.xml b/packages/SystemUI/res/values-hu/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-hu/config.xml
+++ b/packages/SystemUI/res/values-hu/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 4d8b697..faa4a86 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Értesítések"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Alacsony az energiaszint"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> maradt"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> maradt. A takarékos akkumulátorhasználat engedélyezve van."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> maradt. Az Akkumulátorkímélő mód be van kapcsolva."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Az USB-n keresztüli töltés nincs támogatva.\nHasználja a kapott töltőt."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Az USB-n keresztüli töltés nem támogatott."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Kizárólag a tartozékként kapott töltőt használja."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Beállítások"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Bekapcsolja az akkumulátorkímélő módot?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Bekapcsolja az Akkumulátorkímélő módot?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Bekapcsolás"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Akkumulátorkímélő mód bekapcsolása"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Akkumulátorkímélő mód bekapcsolása"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Beállítások"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Képernyő automatikus forgatása"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth megosztva"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Beviteli módok beállítása"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fizikai billentyűzet"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"A(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazás hozzáférhet az USB-eszközhöz?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"A(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazás hozzáférhet az USB-kiegészítőhöz?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"<xliff:g id="ACTIVITY">%1$s</xliff:g> megnyitása, ha USB-kiegészítő csatlakoztatva van?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"<xliff:g id="ACTIVITY">%1$s</xliff:g> megnyitása, ha ez az USB-kiegészítő csatlakoztatva van?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Engedélyezi a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> számára, hogy hozzáférjen a következőhöz: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Engedélyezi a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> számára, hogy hozzáférjen a következőhöz: <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Megnyitja a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazást a(z) <xliff:g id="USB_DEVICE">%2$s</xliff:g> kezeléséhez?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Megnyitja a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazást a(z) <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> kezeléséhez?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"A telepített alkalmazások nem működnek ezzel az USB-kiegészítővel. Bővebben: <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB-kellék"</string>
<string name="label_view" msgid="6304565553218192990">"Megtekintés"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Alapértelmezett használat ehhez az USB-eszközhöz"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Alapértelmezett használat ehhez az USB-kiegészítőhöz"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Mindig a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> nyíljon meg, ha a(z) <xliff:g id="USB_DEVICE">%2$s</xliff:g> csatlakozik"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Mindig a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> nyíljon meg, ha a(z) <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> csatlakozik"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Engedélyezi az USB hibakeresést?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"A számítógép RSA kulcs ujjlenyomata:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Mindig engedélyezze erről a számítógépről"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Az adatforgalom szünetel"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Elérte a beállított adatkorlátot. A továbbiakban nem használ mobiladat-forgalmat.\n\nHa a folytatást választja, szolgáltatója adathasználati díjat számíthat fel."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Folytatás"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nincs internet"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi csatlakoztatva"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS keresése"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"A GPS beállította a helyet"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Aktív helylekérések"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Törli a felhasználót?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"A felhasználóhoz tartozó minden adat és alkalmazás törölve lesz."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Eltávolítás"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Akkumulátorkímélő mód bekapcsolva"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Akkumulátorkímélő mód bekapcsolva"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Csökkenti a teljesítményt és a háttéradatok használatát"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Akkumulátorkímélő mód kikapcsolása"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Akkumulátorkímélő mód kikapcsolása"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"A(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> alkalmazás rögzíteni fog mindent, ami megjelenik a képernyőn."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ne jelenjen meg többé"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Az összes törlése"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d perc</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Akkumulátorhasználat"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Az Akkumulátorkímélő módot töltés közben nem lehet használni"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Akkumulátorkímélő mód"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Az Akkumulátorkímélő módot töltés közben nem lehet használni"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Akkumulátorkímélő mód"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Csökkenti a teljesítményt és a háttéradatok használatát"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> gomb"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Kezdőképernyő"</string>
diff --git a/packages/SystemUI/res/values-hy/config.xml b/packages/SystemUI/res/values-hy/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-hy/config.xml
+++ b/packages/SystemUI/res/values-hy/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 923e4ec..074ca49 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ծանուցումներ"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Մարտկոցի լիցքը սպառվում է"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Մնաց <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Մնաց <xliff:g id="PERCENTAGE">%s</xliff:g>: Մարտկոցի տնտեսումը միացված է:"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Մնացել է <xliff:g id="PERCENTAGE">%s</xliff:g>: Մարտկոցի տնտեսումը միացված է:"</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB լիցքավորումը չի աջակցվում:\nՕգտվեք միայն գործող լիցքավորիչից:"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB լիցքավորումը չի աջակցվում:"</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Օգտագործեք միայն մատակարարի տրամադրած լիցքավորիչը:"</string>
<string name="battery_low_why" msgid="4553600287639198111">"Կարգավորումներ"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Միացնե՞լ մարտկոցի տնտեսումը:"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Միացնե՞լ մարտկոցի տնտեսումը"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Միացնել"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Միացնել մարտկոցի տնտեսումը"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Միացնել մարտկոցի տնտեսումը"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Կարգավորումներ"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Ինքնապտտվող էկրան"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth-ը կապված է"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Կարգավորել մուտքագրման եղանակները"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Ֆիզիկական ստեղնաշար"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Թույլատրե՞լ <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին օգտագործել USB սարքը։"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Թույլատրե՞լ, <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին օգտագործել USB սարքը։"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Բացե՞լ <xliff:g id="ACTIVITY">%1$s</xliff:g>-ը, երբ այս USB կրիչը կապակցված է:"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Բացե՞լ <xliff:g id="ACTIVITY">%1$s</xliff:g>-ը, երբ այս USB լրասարքը կապակցված է:"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Թույլատրե՞լ <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին օգտագործել <xliff:g id="USB_DEVICE">%2$s</xliff:g> լրասարքը։"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Թույլատրե՞լ <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին օգտագործել <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> լրասարքը։"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Բացե՞լ <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածը <xliff:g id="USB_DEVICE">%2$s</xliff:g> լրասարքը մշակելու համար։"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Բացե՞լ <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածը <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> լրասարքը մշակելու համար։"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Այս USB լրասարքի հետ ոչ մի հավելված չի աշխատում: Իմացեք ավելին այս լրասարքի մասին <xliff:g id="URL">%1$s</xliff:g>-ում"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB լրասարք"</string>
<string name="label_view" msgid="6304565553218192990">"Դիտել"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Օգտագործել լռելյայն այս USB սարքի համար"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Օգտագործել լռելյայն այս USB լրասարքի համար"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Միշտ բացել <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածը, երբ <xliff:g id="USB_DEVICE">%2$s</xliff:g> լրասարքը միացված է"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Միշտ բացել <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածը, երբ <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> լրասարքը միացված է"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Թույլատրե՞լ USB-ի կարգաբերումը:"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Համակարգչի RSA-ի բանալի մատնահետքն է`\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Միշտ թույլատրել այս համակարգչից"</string>
@@ -67,8 +67,8 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Ընթացիկ հաշվի օգտատերը չի կարող միացնել USB վրիպազերծումը: Այս գործառույթը միացնելու համար մուտք գործեք հիմնական օգտատիրոջ հաշվով:"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Խոշորացնել` էկրանը լցնելու համար"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Ձգել` էկրանը լցնելու համար"</string>
- <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Պահում է էկրանի պատկերը…"</string>
- <string name="screenshot_saving_title" msgid="8242282144535555697">"Պահում է էկրանի պատկերը..."</string>
+ <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Էկրանի պատկերը պահվում է…"</string>
+ <string name="screenshot_saving_title" msgid="8242282144535555697">"Էկրանի պատկերը պահվում է..."</string>
<string name="screenshot_saving_text" msgid="2419718443411738818">"Էկրանի պատկերը պահվում է:"</string>
<string name="screenshot_saved_title" msgid="6461865960961414961">"Էկրանի պատկերը լուսանկարվել է:"</string>
<string name="screenshot_saved_text" msgid="2685605830386712477">"Հպեք՝ էկրանի պատկերը տեսնելու համար:"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Տվյալների օգտագործումը դադարեցված է"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Տվյալների օգտագործման նշված սահմանաչափը լրացել է: Դուք բջջային տվյալներ այլևս չեք օգտագործում:\n\nԵթե վերսկսեք օգտագործումը, տվյալների օգտագործման համար կարող են գանձվել վճարներ:"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Վերսկսել"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ինտերնետ կապ չկա"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ը միացված է"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Որոնում է GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Տեղադրությունը կարգավորվել է GPS-ի կողմից"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Տեղադրության հարցումներն ակտիվ են"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Հեռացնե՞լ օգտատիրոջը:"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Այս օգտատիրոջ բոլոր հավելվածներն ու տվյալները կջնջվեն:"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Հեռացնել"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Մարտկոցի տնտեսումը միացված է"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Մարտկոցի տնտեսումը միացված է"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Նվազեցնում է ծանրաբեռնվածությունը և ֆոնային տվյալները"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Անջատել մարտկոցի տնտեսումը"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Անջատել մարտկոցի տնտեսումը"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ծրագիրը կսկսի հավաքել այն ամենն ինչ ցուցադրվում է ձեր էկրանին:"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Այլևս ցույց չտալ"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Մաքրել բոլորը"</string>
@@ -582,8 +580,8 @@
<item quantity="other">%d րոպե</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Մարտկոցի օգտագործում"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Մարտկոցի էներգախնայիչը լիցքավորման ժամանակ հասանելի չէ"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Մարտկոցի էներգախնայիչ"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Մարտկոցի տնտեսումը լիցքավորման ժամանակ հասանելի չէ"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Մարտկոցի տնտեսում"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Նվազեցնում է ծանրաբեռնվածությունը և ֆոնային տվյալները"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> կոճակ"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Գլխավոր էջ"</string>
diff --git a/packages/SystemUI/res/values-in/config.xml b/packages/SystemUI/res/values-in/config.xml
index 9857f13..477f219 100644
--- a/packages/SystemUI/res/values-in/config.xml
+++ b/packages/SystemUI/res/values-in/config.xml
@@ -22,7 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for config_overviewServiceComponent (2288311504315574053) -->
- <skip />
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 255ba2c..b4709bb 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifikasi"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Baterai lemah"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Tersisa <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Tersisa <xliff:g id="PERCENTAGE">%s</xliff:g>. Penghemat baterai aktif."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Tersisa <xliff:g id="PERCENTAGE">%s</xliff:g>. Penghemat Baterai aktif."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Pengisian daya USB tidak didukung.\nGunakan hanya pengisi daya yang disediakan."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Pengisian daya USB tidak didukung."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Hanya gunakan pengisi daya yang disediakan."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Setelan"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Aktifkan penghemat baterai?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Aktifkan Penghemat Baterai?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Aktifkan"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Aktifkan penghemat baterai"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Aktifkan Penghemat Baterai"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Setelan"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rotasi layar otomatis"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tertambat"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Menyiapkan metode masukan"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Keyboard fisik"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Izinkan apl <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses perangkat USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Izinkan apl <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses aksesori USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Buka <xliff:g id="ACTIVITY">%1$s</xliff:g> ketika perangkat USB ini tersambung?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Buka <xliff:g id="ACTIVITY">%1$s</xliff:g> ketika aksesori USB ini tersambung?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Izinkan <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Izinkan <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Buka <xliff:g id="APPLICATION">%1$s</xliff:g> untuk menangani <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Buka <xliff:g id="APPLICATION">%1$s</xliff:g> untuk menangani <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Tidak ada apl terpasang yang bekerja dengan aksesori USB ini. Pelajari lebih lanjut tentang aksesori ini di <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Aksesori USB"</string>
<string name="label_view" msgid="6304565553218192990">"Lihat"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Gunakan secara default untuk perangkat USB ini"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Gunakan secara default untuk aksesori USB ini"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Selalu buka <xliff:g id="APPLICATION">%1$s</xliff:g> saat <xliff:g id="USB_DEVICE">%2$s</xliff:g> terhubung"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Selalu buka <xliff:g id="APPLICATION">%1$s</xliff:g> saat <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> terhubung"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Izinkan debugging USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Sidik jari kunci RSA komputer adalah:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Selalu izinkan dari komputer ini"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data dijeda"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Batas data yang Anda tetapkan telah tercapai. Anda tidak menggunakan data seluler lagi.\n\nJika Anda melanjutkan, tarif penggunaan data mungkin berlaku."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Lanjutkan"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tidak ada sambungan internet"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tersambung"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Menelusuri GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasi yang disetel oleh GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Permintaan lokasi aktif"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Hapus pengguna?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Semua aplikasi dan data pengguna ini akan dihapus."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Hapus"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Penghemat baterai aktif"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Penghemat Baterai aktif"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Mengurangi kinerja dan data latar belakang"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Nonaktifkan penghemat baterai"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Nonaktifkan Penghemat Baterai"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> akan mulai menangkap apa saja yang ditampilkan pada layar Anda."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Jangan tampilkan lagi"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Hapus semua"</string>
@@ -571,7 +569,7 @@
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrol notifikasi"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"opsi tunda notifikasi"</string>
- <string name="snooze_undo" msgid="6074877317002985129">"URUNG"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"URUNGKAN"</string>
<string name="snoozed_for_time" msgid="2390718332980204462">"Ditunda selama <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<plurals name="snoozeHourOptions" formatted="false" msgid="2124335842674413030">
<item quantity="other">%d jam</item>
@@ -582,8 +580,8 @@
<item quantity="one">%d menit</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Pemakaian baterai"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Penghemat baterai tidak tersedia selama mengisi daya"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Penghemat baterai"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Penghemat Baterai tidak tersedia selama pengisian daya"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Penghemat Baterai"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Mengurangi performa dan data latar belakang"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Tombol <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
@@ -758,7 +756,8 @@
<string name="instant_apps" msgid="6647570248119804907">"Aplikasi Instan"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Aplikasi instan tidak perlu diinstal."</string>
<string name="app_info" msgid="6856026610594615344">"Info aplikasi"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Buka di web"</string>
+ <!-- no translation found for go_to_web (2650669128861626071) -->
+ <skip />
<string name="mobile_data" msgid="7094582042819250762">"Data seluler"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi nonaktif"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth nonaktif"</string>
diff --git a/packages/SystemUI/res/values-is/config.xml b/packages/SystemUI/res/values-is/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-is/config.xml
+++ b/packages/SystemUI/res/values-is/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 58bdc3b..f60a766 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Tilkynningar"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Rafhlaðan er að tæmast"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> eftir"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> eftir. Kveikt er á rafhlöðusparnaði."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> eftir. Kveikt er á rafhlöðusparnaði."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-hleðsla er ekki studd.\nNotaðu eingöngu hleðslutækið sem fylgdi."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Ekki er stuðningur við USB-hleðslu."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Notaðu eingöngu hleðslutækið sem fylgir með."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Stillingar"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Kveikja á rafhlöðusparnaði?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Kveikja á rafhlöðusparnaði?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Kveikja"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Kveikja á rafhlöðusparnaði"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Kveikja á rafhlöðusparnaði"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Stillingar"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Snúa skjá sjálfkrafa"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Tjóðrað um Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Setja upp innsláttaraðferðir"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Vélbúnaðarlyklaborð"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Veita forritinu <xliff:g id="APPLICATION">%1$s</xliff:g> aðgang að USB-tækinu?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Veita forritinu <xliff:g id="APPLICATION">%1$s</xliff:g> aðgang að USB-aukabúnaðinum?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Opna <xliff:g id="ACTIVITY">%1$s</xliff:g> þegar þetta USB-tæki er tengt?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Opna <xliff:g id="ACTIVITY">%1$s</xliff:g> þegar þessi USB-aukabúnaður er tengdur?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Viltu veita <xliff:g id="APPLICATION">%1$s</xliff:g> aðgang að <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Viltu veita <xliff:g id="APPLICATION">%1$s</xliff:g> aðgang að <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Viltu opna <xliff:g id="APPLICATION">%1$s</xliff:g> til að sjá um <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Viltu opna <xliff:g id="APPLICATION">%1$s</xliff:g> til að sjá um <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Engin uppsett forrit virka með þessum USB-aukabúnaði. Frekari upplýsingar eru á <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB-aukabúnaður"</string>
<string name="label_view" msgid="6304565553218192990">"Skoða"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Nota sjálfgefið fyrir þetta USB-tæki"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Nota sjálfgefið fyrir þennan USB-aukabúnað"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Opna alltaf <xliff:g id="APPLICATION">%1$s</xliff:g> þegar <xliff:g id="USB_DEVICE">%2$s</xliff:g> er tengt"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Opna alltaf <xliff:g id="APPLICATION">%1$s</xliff:g> þegar <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> er tengt"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Leyfa USB-villuleit?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Fingrafar RSA-lykils tölvunnar er:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Leyfa alltaf úr þessari tölvu"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Slökkt er á gagnanotkun"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Gagnamörkunum sem þú stilltir hefur verið náð. Þú ert ekki lengur að nota farsímagögn.\n\nEf þú heldur áfram gætu gjöld verið innheimt fyrir gagnanotkun."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Halda áfram"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Engin nettenging"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tengt"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Leitar að GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Staðsetning valin með GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Staðsetningarbeiðnir virkar"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Fjarlægja notandann?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Öllum forritum og gögnum þessa notanda verður eytt."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Fjarlægja"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Kveikt er á rafhlöðusparnaði"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Kveikt er á rafhlöðusparnaði"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Dregur úr afköstum og bakgrunnsgögnum"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Slökkva á rafhlöðusparnaði"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Slökkva á rafhlöðusparnaði"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> mun fanga allt sem birtist á skjánum."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ekki sýna þetta aftur"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Hreinsa allt"</string>
@@ -582,8 +580,8 @@
<item quantity="other">%d mínútur</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Rafhlöðunotkun"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Ekki er hægt að nota rafhlöðusparnað meðan á hleðslu stendur"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Rafhlöðusparnaður"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ekki er hægt að nota rafhlöðusparnað meðan á hleðslu stendur"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Rafhlöðusparnaður"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Dregur úr afköstum og bakgrunnsgögnum"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Hnappur <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-it/config.xml b/packages/SystemUI/res/values-it/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-it/config.xml
+++ b/packages/SystemUI/res/values-it/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 56d5348..d4e6314 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifiche"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Batteria quasi scarica"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> rimanente"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> rimanente. Risparmio energetico attivo."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> rimanente. Risparmio energetico attivo."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Ricarica tramite USB non supportata.\nUtilizza solo il caricatore in dotazione."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Ricarica tramite USB non supportata."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Utilizza solo il caricabatterie fornito in dotazione."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Impostazioni"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Attivare il risparmio energetico?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Attivare Risparmio energetico?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Attiva"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Attiva risparmio energetico"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Attiva Risparmio energetico"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Impostazioni"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rotazione automatica schermo"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth con tethering"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configura metodi di immissione"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Tastiera fisica"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Consentire all\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> di accedere al dispositivo USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Consentire all\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> di accedere all\'accessorio USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Aprire <xliff:g id="ACTIVITY">%1$s</xliff:g> quando questo dispositivo USB è collegato?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Aprire <xliff:g id="ACTIVITY">%1$s</xliff:g> quando questo accessorio USB è collegato?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Vuoi consentire a <xliff:g id="APPLICATION">%1$s</xliff:g> di accedere a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Vuoi consentire a <xliff:g id="APPLICATION">%1$s</xliff:g> di accedere a <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Vuoi aprire <xliff:g id="APPLICATION">%1$s</xliff:g> per gestire <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Vuoi aprire <xliff:g id="APPLICATION">%1$s</xliff:g> per gestire <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Nessuna app installata funziona con questo accessorio USB. Altre info su <xliff:g id="URL">%1$s</xliff:g>."</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Accessorio USB"</string>
<string name="label_view" msgid="6304565553218192990">"Visualizza"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Usa per impostazione predef. per dispositivo USB"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Usa per impostazione predef. per accessorio USB"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Apri sempre <xliff:g id="APPLICATION">%1$s</xliff:g> quando si collega <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Apri sempre <xliff:g id="APPLICATION">%1$s</xliff:g> quando si collega <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Consentire debug USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Fingerprint della chiave RSA del computer: \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Consenti sempre da questo computer"</string>
@@ -245,8 +245,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dati sospesi"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"È stato raggiunto il limite di dati impostato. I dati mobili sono stati disattivati.\n\nSe li riattivi, potrebbero essere applicati costi per l\'utilizzo dei dati."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Riprendi"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nessuna connessione"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connesso"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Ricerca del GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Posizione stabilita dal GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Richieste di accesso alla posizione attive"</string>
@@ -403,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Rimuovere l\'utente?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Tutte le app e i dati di questo utente verranno eliminati."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Rimuovi"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Risparmio energetico attivo"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Risparmio energetico attivo"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Riduce le prestazioni e i dati in background"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Disattiva risparmio energetico"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Disattiva Risparmio energetico"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> inizierà ad acquisire tutto ciò che è visualizzato sul tuo schermo."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Non mostrare più"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Cancella tutto"</string>
@@ -478,9 +476,9 @@
<string name="volume_zen_end_now" msgid="6930243045593601084">"Disattiva ora"</string>
<string name="accessibility_volume_expand" msgid="5946812790999244205">"Espandi"</string>
<string name="accessibility_volume_collapse" msgid="3609549593031810875">"Comprimi"</string>
- <string name="screen_pinning_title" msgid="3273740381976175811">"La schermata è bloccata"</string>
- <string name="screen_pinning_description" msgid="8909878447196419623">"La schermata rimane visibile finché non viene disattivato il blocco su schermo. Per disattivarlo, tieni premuto Indietro e Panoramica."</string>
- <string name="screen_pinning_description_accessible" msgid="426190689254018656">"La schermata rimane visibile finché non viene disattivato il blocco su schermo. Per disattivarlo, tieni premuto Panoramica."</string>
+ <string name="screen_pinning_title" msgid="3273740381976175811">"La schermata è fissata"</string>
+ <string name="screen_pinning_description" msgid="8909878447196419623">"La schermata rimane visibile finché non viene sganciata. Per sganciarla, tieni premuto Indietro e Panoramica."</string>
+ <string name="screen_pinning_description_accessible" msgid="426190689254018656">"La schermata rimane visibile finché non viene sganciata. Per sganciarla, tieni premuto Panoramica."</string>
<string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
<string name="screen_pinning_negative" msgid="3741602308343880268">"No, grazie"</string>
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Nascondere <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -584,8 +582,8 @@
<item quantity="one">%d minuto</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Utilizzo batteria"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Risparmio energetico non disponibile durante la ricarica"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Risparmio energetico"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Risparmio energetico non disponibile durante la ricarica"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Risparmio energetico"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Riduce le prestazioni e i dati in background"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Pulsante <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home page"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index dcef8c6..f20275d 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -36,14 +36,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"התראות"</string>
<string name="battery_low_title" msgid="6456385927409742437">"עוצמת הסוללה נמוכה"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"נותרו <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"נותרו <xliff:g id="PERCENTAGE">%s</xliff:g>. הופעל שירות חיסכון בסוללה."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"נותרו <xliff:g id="PERCENTAGE">%s</xliff:g>. הופעלה תכונת החיסכון בסוללה."</string>
<string name="invalid_charger" msgid="4549105996740522523">"טעינה באמצעות USB אינה נתמכת.\nהשתמש אך ורק במטען שסופק."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"טעינה בחיבור USB אינה נתמכת."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"השתמש רק במטען שסופק."</string>
<string name="battery_low_why" msgid="4553600287639198111">"הגדרות"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"להפעיל חיסכון בסוללה?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"להפעיל את תכונת החיסכון בסוללה?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"הפעל"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"הפעל חיסכון בסוללה"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"הפעלת תכונת החיסכון בסוללה"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"הגדרות"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"סיבוב אוטומטי של המסך"</string>
@@ -53,21 +53,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth קשור"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"הגדר שיטות קלט"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"מקלדת פיזית"</string>
- <!-- no translation found for usb_device_permission_prompt (1825685909587559679) -->
- <skip />
- <!-- no translation found for usb_accessory_permission_prompt (2465531696941369047) -->
- <skip />
- <!-- no translation found for usb_device_confirm_prompt (7440562274256843905) -->
- <skip />
- <!-- no translation found for usb_accessory_confirm_prompt (4333670517539993561) -->
- <skip />
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"האם לתת לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g> גישה אל <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"האם לתת לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g> גישה אל <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"האם לפתוח את <xliff:g id="APPLICATION">%1$s</xliff:g> כדי לעבוד עם <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"האם לפתוח את <xliff:g id="APPLICATION">%1$s</xliff:g> כדי לעבוד עם <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"אין אפליקציות מותקנות הפועלות עם אביזר ה-USB. למידע נוסף על אביזר זה היכנס לכתובת <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"אביזר USB"</string>
<string name="label_view" msgid="6304565553218192990">"הצג"</string>
- <!-- no translation found for always_use_device (4015357883336738417) -->
- <skip />
- <!-- no translation found for always_use_accessory (3257892669444535154) -->
- <skip />
+ <string name="always_use_device" msgid="4015357883336738417">"האפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g> תמיד תיפתח כשהאביזר <xliff:g id="USB_DEVICE">%2$s</xliff:g> יחובר"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"האפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g> תמיד תיפתח כשהאביזר <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> יחובר"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"האם לאפשר ניפוי באגים ב-USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"טביעת האצבע של מפתח ה-RSA של המחשב היא:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"אפשר תמיד ממחשב זה"</string>
@@ -251,8 +245,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"השימוש בנתונים מושהה"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"הגעת למגבלת הנתונים שהגדרת. אתה כבר לא משתמש בחבילת גלישה.\n\nאם תמשיך, ייתכנו חיובים על שימוש בנתונים."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"המשך"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"אין חיבור לאינטרנט"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi מחובר"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"מחפש GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"מיקום מוגדר על ידי GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"בקשות מיקום פעילות"</string>
@@ -411,9 +403,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"האם להסיר את המשתמש?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"כל האפליקציות והנתונים של המשתמש הזה יימחקו."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"הסר"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"תכונת \'חיסכון בסוללה\' פועלת"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"תכונת החיסכון בסוללה פועלת"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"מפחית את הביצועים ונתונים ברקע"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"כבה את החיסכון בסוללה"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"כיבוי תכונת החיסכון בסוללה"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> יתחיל להקליט את כל התוכן המוצג במסך שלך."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"אל תציג שוב"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"נקה הכל"</string>
@@ -600,8 +592,8 @@
<item quantity="one">דקה</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"שימוש בסוללה"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"תכונת החיסכון בסוללה לא זמינה כשהמכשיר בטעינה"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"חיסכון בסוללה"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"תכונת החיסכון בסוללה אינה זמינה בעת טעינת המכשיר"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"חיסכון בסוללה"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"מפחית את רמת הביצועים ואת נתוני הרקע"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"לחצן <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"דף הבית"</string>
diff --git a/packages/SystemUI/res/values-ja/config.xml b/packages/SystemUI/res/values-ja/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-ja/config.xml
+++ b/packages/SystemUI/res/values-ja/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index ac29ca7..ac83c2d 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
<string name="battery_low_title" msgid="6456385927409742437">"電池残量が少なくなっています"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"残量が<xliff:g id="PERCENTAGE">%s</xliff:g>です"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"残量が<xliff:g id="PERCENTAGE">%s</xliff:g>です。バッテリーセーバーはONです。"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"残量が <xliff:g id="PERCENTAGE">%s</xliff:g> です。バッテリー セーバーは ON です。"</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB充電には対応していません。\n付属の充電器をお使いください。"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB充電には対応していません。"</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"専用の充電器のみを使用してください。"</string>
<string name="battery_low_why" msgid="4553600287639198111">"設定"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"バッテリーセーバーをONにしますか?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"バッテリー セーバーを ON にしますか?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"ONにする"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"バッテリーセーバーをONにします"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"バッテリー セーバーを ON"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"設定"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"自動回転画面"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetoothテザリング接続"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"入力方法をセットアップ"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"物理キーボード"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"アプリ「<xliff:g id="APPLICATION">%1$s</xliff:g>」にUSBデバイスへのアクセスを許可しますか?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"アプリ「<xliff:g id="APPLICATION">%1$s</xliff:g>」にUSBアクセサリへのアクセスを許可しますか?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"このUSBデバイスが接続されたときに<xliff:g id="ACTIVITY">%1$s</xliff:g>を開きますか?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"このUSBアクセサリが接続されたときに<xliff:g id="ACTIVITY">%1$s</xliff:g>を開きますか?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> に <xliff:g id="USB_DEVICE">%2$s</xliff:g> へのアクセスを許可しますか?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> に <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> へのアクセスを許可しますか?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="APPLICATION">%1$s</xliff:g> を起動して <xliff:g id="USB_DEVICE">%2$s</xliff:g> を処理しますか?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="APPLICATION">%1$s</xliff:g> を起動して <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> を処理しますか?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"このUSBアクセサリを扱うアプリはインストールされていません。詳細: <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USBアクセサリ"</string>
<string name="label_view" msgid="6304565553218192990">"表示"</string>
- <string name="always_use_device" msgid="1450287437017315906">"このUSBデバイスにデフォルトで使用する"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"このUSBアクセサリにデフォルトで使用する"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> を接続したら常に <xliff:g id="APPLICATION">%1$s</xliff:g> を起動する"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> を接続したら常に <xliff:g id="APPLICATION">%1$s</xliff:g> を起動する"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USBデバッグを許可しますか?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"このパソコンのRSAキーのフィンガープリント:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"このパソコンからのUSBデバッグを常に許可する"</string>
@@ -245,8 +245,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"データの一時停止"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"設定したデータ上限に達しました。現在モバイルデータは使用できません。\n\n再開する場合は、データ使用量について請求が発生する可能性があります。"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"再開"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"インターネット未接続"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi接続済み"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPSで検索中"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPSにより現在地が設定されました"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"現在地リクエストがアクティブ"</string>
@@ -403,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"ユーザーを削除しますか?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"このユーザーのアプリとデータがすべて削除されます。"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"削除"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"バッテリーセーバーがON"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"バッテリー セーバー ON"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"パフォーマンスとバックグラウンドデータを制限します"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"バッテリーセーバーをOFFにします"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"バッテリー セーバーを OFF"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>で、画面に表示されているコンテンツのキャプチャを開始します。"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"次回から表示しない"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"すべて消去"</string>
@@ -584,8 +582,8 @@
<item quantity="one">%d分</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"電池の使用状況"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"充電中はバッテリー セーバーは利用できません"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"バッテリー セーバー"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"充電中はバッテリー セーバーは利用できません"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"バッテリー セーバー"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"パフォーマンスとバックグラウンド データを制限します"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> ボタン"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-ka/config.xml b/packages/SystemUI/res/values-ka/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-ka/config.xml
+++ b/packages/SystemUI/res/values-ka/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 6750756..e871c6a 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"შეტყობინებები"</string>
<string name="battery_low_title" msgid="6456385927409742437">"ბატარეა იწურება"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"დარჩენილია <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"დარჩენილია <xliff:g id="PERCENTAGE">%s</xliff:g>. ბატარეის დაზოგვა ჩართულია."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"დარჩენილია <xliff:g id="PERCENTAGE">%s</xliff:g>. ბატარეის დამზოგი ჩართულია."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-ით დატენვა არ არის მხარდაჭერილი.\nგამოიყენეთ მხოლოდ ელექტრო-დამტენი."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB დატენვა მხარდაჭერილი არ არის."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"გამოიყენეთ მხოლოდ მოყოლილი დამტენი."</string>
<string name="battery_low_why" msgid="4553600287639198111">"პარამეტრები"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"გსურთ ბატარეის დაზოგვის ჩართვა?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"გსურთ ბატარეის დამზოგის ჩართვა?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"ჩართვა"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"ბატარეის დაზოგვის ჩართვა"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"ბატარეის დამზოგის ჩართვა"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"პარამეტრები"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"ავტოროტაციის ეკრანი"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth მიერთებულია."</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"შეყვანის მეთოდების დაყენება"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"ფიზიკური კლავიატურა"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"გსურთ, მისცეთ აპლიკაციას „<xliff:g id="APPLICATION">%1$s</xliff:g>“ USB მეხსიერებასთან წვდომის უფლება?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"გსურთ, მისცეთ აპლიკაციას „<xliff:g id="APPLICATION">%1$s</xliff:g>“ USB აქსესუართან წვდომის უფლება?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"გსურთ <xliff:g id="ACTIVITY">%1$s</xliff:g> , როდესაც ეს USB მოწყობილობა შეერთებულია?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"გსურთ <xliff:g id="ACTIVITY">%1$s</xliff:g> , როდესაც ეს USB მოწყობილობა შეერთებულია?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"მიეცეს <xliff:g id="APPLICATION">%1$s</xliff:g>-ს <xliff:g id="USB_DEVICE">%2$s</xliff:g>-ზე წვდომის უფლება?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"მიეცეს <xliff:g id="APPLICATION">%1$s</xliff:g>-ს <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>-ზე წვდომის უფლება?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"გსურთ, გახსნათ <xliff:g id="APPLICATION">%1$s</xliff:g>, <xliff:g id="USB_DEVICE">%2$s</xliff:g>-ის გამოსაყენებლად?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"გსურთ, გახსნათ <xliff:g id="APPLICATION">%1$s</xliff:g>, <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>-ის გამოსაყენებლად?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"არცერთი დაყენებული აპი არ მუშაობს ამ USB აქსესუართან. შეიტყვეთ მეტი ამ აქსესუარის შესახებ <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB აქსესუარი"</string>
<string name="label_view" msgid="6304565553218192990">"ნახვა"</string>
- <string name="always_use_device" msgid="1450287437017315906">"ამ USB მოწყობილობის ნაგულისხმევად გამოყენება"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"ავტომატურად გამოიყენე ამ USB აქსესუარისთვის."</string>
+ <string name="always_use_device" msgid="4015357883336738417">"ყოველთვის გაიხსნას <xliff:g id="APPLICATION">%1$s</xliff:g>, როცა <xliff:g id="USB_DEVICE">%2$s</xliff:g> დაკავშირებულია"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"ყოველთვის გაიხსნას <xliff:g id="APPLICATION">%1$s</xliff:g>, როცა <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> დაკავშირებულია"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"გააქტიურდეს USB გამართვა?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"კომპიუტერის RSA გასაღების თითის ანაბეჭდია:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"ყოველთვის დართე ნება ამ კომპიუტერიდან."</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"მონაცემები შეჩერებულია"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"მიღწეულია მონაცემთა მოხმარების თქვენ მიერ მითითებული ლიმიტი. ამიტომ, მობილური ინტერნეტის გამოყენება აღარ ხდება.\n\nგანახლების შემთხვევაში, შეიძლება მობილური ინტერნეტის საფასურის გადახდა მოგიწიოთ."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"გაგრძელება"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ინტერნეტ კავშირი არ არის"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi დაკავშირებულია"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS-ის ძებნა"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS-ით დადგენილი მდებარეობა"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"მდებარეობის მოთხოვნები აქტიურია"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"გსურთ მომხმარებლის წაშლა?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"ამ მომხმარებლის ყველა აპი და მონაცემი წაიშლება."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"წაშლა"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"ბატარეის დამზოგი ჩართულია"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"ბატარეის დამზოგი ჩართულია"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ამცირებს წარმადობას და უკანა ფონის მონაცემებს"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ბატარეის დაზოგვის გამორთვა"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"ბატარეის დამზოგის გამორთვა"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> დაიწყებს იმ ყველაფრის აღბეჭდვას, რაც თქვენს ეკრანზე ჩანს."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"აღარ მაჩვენო"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"ყველას გასუფთავება"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d წუთი</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"ბატარეის მოხმარება"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"ბატარეის დამზოგი დატენვისას მიუწვდომელია"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"ბატარეის დამზოგი"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ბატარეის დამზოგი დატენვისას მიწვდომელია"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"ბატარეის დამზოგი"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"ამცირებს წარმადობას და ფონურ მონაცემებს"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"ღილაკი „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
@@ -758,7 +756,8 @@
<string name="instant_apps" msgid="6647570248119804907">"მყისიერი აპები"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"მყისიერი აპები ინსტალაციას არ საჭიროებს."</string>
<string name="app_info" msgid="6856026610594615344">"აპის შესახებ"</string>
- <string name="go_to_web" msgid="1106022723459948514">"ვებზე გადასვლა"</string>
+ <!-- no translation found for go_to_web (2650669128861626071) -->
+ <skip />
<string name="mobile_data" msgid="7094582042819250762">"მობილური ინტერნეტი"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi გამორთულია"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth გამორთულია"</string>
diff --git a/packages/SystemUI/res/values-kk/config.xml b/packages/SystemUI/res/values-kk/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-kk/config.xml
+++ b/packages/SystemUI/res/values-kk/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 38d84c4..f2b4fc8 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Хабарлар"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Батарея заряды төмен"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> қалды"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> қалды. Батарея үнемдегіш қосулы."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> қалды. Battery Saver қосулы."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB зарядтауды қолдау ұсынылмаған.\nЖабдықталған зарядтағыш құрылғысын ғана қолданыңыз."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB арқылы зарядтауға қолдау көрсетілмейді."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Тек жинақтағы зарядтағышты пайдаланыңыз."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Параметрлер"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Батарея үнемдегішті қосу керек пе?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Battery Saver функциясы қосылсын ба?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Қосу"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Батарея үнемдегішін қосу"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Battery saver функциясын қосу"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Параметрлер"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Авто айналатын экран"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth қосылды"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Енгізу әдістерін орнату"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Қатты пернетақта"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"<xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасы USB құрылғысына кірсін бе?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"<xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына USB жабдығына кіруге рұқсат беру?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Осы USB құрылғысы қосылғанда <xliff:g id="ACTIVITY">%1$s</xliff:g> әрекеті ашылсын ба?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Осы USB жабдығы қосылғанда <xliff:g id="ACTIVITY">%1$s</xliff:g> әрекеті ашылсын ба?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына <xliff:g id="USB_DEVICE">%2$s</xliff:g> құрылғысына кіруге рұқсат берілсін бе?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> жабдығына кіруге рұқсат берілсін бе?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> жабдығын басқару үшін <xliff:g id="APPLICATION">%1$s</xliff:g> ашылсын ба?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> жабдығын басқару үшін <xliff:g id="APPLICATION">%1$s</xliff:g> ашылсын ба?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Орнатылған қолданбалар осы USB жабдығымен жұмыс жасамайды.Жабдықты <xliff:g id="URL">%1$s</xliff:g> ден қараңыз."</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB жабдығы"</string>
<string name="label_view" msgid="6304565553218192990">"Көрініс"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Бұл USB құрылғысы үшін бастапқы параметрін қолданыңыз."</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Бұл USB жабдығы үшін бастапқы параметрін қолданыңыз."</string>
+ <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> қосылған кезде, <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасын ашу"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> қосылған кезде, <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасын ашу"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB жөндеуге рұқсат берілсін бе?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Бұл компьютердің RSA перне саусақ таңбасы:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Осы компьютерден әрқашан рұқсат беру"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Деректер кідіртілді"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Белгіленген деректер шегіне жеттіңіз. Мобильдік деректер енді пайдаланылмайды.\n\nЕгер жалғастырсаңыз, деректер трафигі үшін ақы алынуы мүмкін."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Жалғастыру"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланысы жоқ"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi қосулы"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS қызметін іздеуде"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Орын GPS арқылы орнатылған"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Орын өтініштері қосылған"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Пайдаланушы жойылсын ба?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Осы пайдаланушының барлық қолданбалары мен деректері жойылады."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Жою"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Батарея үнемдегіш қосулы"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Battery saver қосулы"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Өнімділікті және фондық деректерді азайтады"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Батарея үнемдегішті өшіру"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Battery saver функциясын өшіру"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> экранда көрсетілгеннің барлығын түсіре бастайды."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Қайта көрсетпеу"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Барлығын тазалау"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d минут</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Батареяны пайдалану"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Зарядтау кезінде \"Battery saver\" функциясы қол жетімді емес"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Battery saver"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Зарядтау кезінде Батарея үнемдегіш қол жетімді емес"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Батарея үнемдегіш"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Өнімділікті және фондық деректерді азайтады"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> түймесі"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-km/config.xml b/packages/SystemUI/res/values-km/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-km/config.xml
+++ b/packages/SystemUI/res/values-km/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 097d21d..ad9b057 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"ការជូនដំណឹង"</string>
<string name="battery_low_title" msgid="6456385927409742437">"ជិតអស់ថ្មហើយ"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"នៅសល់ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"នៅសល់ <xliff:g id="PERCENTAGE">%s</xliff:g> ។ កម្មវិធីសន្សំថ្មគឺបើក។"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"នៅសល់ <xliff:g id="PERCENTAGE">%s</xliff:g> ។ កម្មវិធីសន្សំថ្មបានបើក។"</string>
<string name="invalid_charger" msgid="4549105996740522523">"មិនគាំទ្រការបញ្ចូលតាមយូអេសប៊ី។\nប្រើតែឧបករណ៍បញ្ចូលថ្មដែលបានផ្ដល់។"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"មិនគាំទ្រការបញ្ចូលថ្មតាមយូអេសប៊ីទេ។"</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"ប្រើតែឧបករណ៍បញ្ចូលថ្មដែលបានផ្ដល់ឲ្យ។"</string>
<string name="battery_low_why" msgid="4553600287639198111">"ការកំណត់"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"បើកធាតុរក្សាថាមពលថ្ម?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"បើកកម្មវិធីសន្សំថ្ម?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"បើក"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"បើកធាតុរក្សាថាមពលថ្ម"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"បើកកម្មវិធីសន្សំថ្ម"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ការកំណត់"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"វ៉ាយហ្វាយ"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"បង្វិលអេក្រង់ស្វ័យប្រវត្តិ"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"បានភ្ជាប់ប៊្លូធូស"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"រៀបចំវិធីសាស្ត្របញ្ចូល"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"ក្ដារចុចពិតប្រាកដ"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"ឲ្យកម្មវិធី <xliff:g id="APPLICATION">%1$s</xliff:g> ចូលដំណើរការឧបករណ៍យូអេសប៊ី?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"ឲ្យកម្មវិធី <xliff:g id="APPLICATION">%1$s</xliff:g> ចូលដំណើរការឧបករណ៍យូអេសប៊ី?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"បើក <xliff:g id="ACTIVITY">%1$s</xliff:g> ពេលបានភ្ជាប់ឧបករណ៍យូអេសប៊ីនេះ?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"បើក <xliff:g id="ACTIVITY">%1$s</xliff:g> ពេលបានភ្ជាប់ឧបករណ៍យូអេសប៊ី?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"អនុញ្ញាត <xliff:g id="APPLICATION">%1$s</xliff:g> ឱ្យចូលប្រើ <xliff:g id="USB_DEVICE">%2$s</xliff:g> មែនទេ?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"អនុញ្ញាត <xliff:g id="APPLICATION">%1$s</xliff:g> ឱ្យចូលប្រើ <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> មែនទេ?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"បើក <xliff:g id="APPLICATION">%1$s</xliff:g> ដើម្បីគ្រប់គ្រង <xliff:g id="USB_DEVICE">%2$s</xliff:g> មែនទេ?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"បើក <xliff:g id="APPLICATION">%1$s</xliff:g> ដើម្បីគ្រប់គ្រង <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> មែនទេ?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"គ្មានកម្មវិធីបានដំឡើងដំណើរការជាមួយឧបករណ៍យូអេសប៊ី។ ស្វែងយល់បន្ថែមអំពីឧបករណ៍នេះនៅ <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"ឧបករណ៍យូអេសប៊ី"</string>
<string name="label_view" msgid="6304565553218192990">"មើល"</string>
- <string name="always_use_device" msgid="1450287437017315906">"ប្រើតាមលំនាំដើមសម្រាប់ឧបករណ៍យូអេសប៊ីនេះ"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"ប្រើតាមលំនាំដើមសម្រាប់ខ្សែយូអេសប៊ីនេះ"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"បើក <xliff:g id="APPLICATION">%1$s</xliff:g> ជានិច្ចនៅពេលដែល <xliff:g id="USB_DEVICE">%2$s</xliff:g> ត្រូវបានភ្ជាប់"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"បើក <xliff:g id="APPLICATION">%1$s</xliff:g> ជានិច្ចនៅពេលដែល <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ត្រូវបានភ្ជាប់"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"អនុញ្ញាតការកែកំហុសយូអេសប៊ី?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"ស្នាមម្រាមដៃ RSA របស់កុំព្យូទ័រគឺ៖ \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"អនុញ្ញាតជានិច្ចសម្រាប់កុំព្យូទ័រនេះ"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ទិន្នន័យត្រូវបានផ្អាក"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"បានឈានដល់កម្រិតទិន្នន័យដែលអ្នកបានកំណត់ហើយ។ ឥឡូវអ្នកមិនប្រើទិន្នន័យទូរសព្ទចល័តទៀតទេ។\n\nអាចនឹងគិតថ្លៃលើការប្រើទិន្នន័យ ប្រសិនបើអ្នកបន្តប្រើឡើងវិញ។"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"បន្ត"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"គ្មានការតភ្ជាប់អ៊ីនធឺណិត"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"បានភ្ជាប់វ៉ាយហ្វាយ"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"ស្វែងរក GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"ទីតាំងកំណត់ដោយ GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"សំណើទីតាំងសកម្ម"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"យកអ្នកប្រើចេញ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"កម្មវិធី និងទិន្នន័យទាំងអស់របស់អ្នកប្រើនេះនឹងត្រូវបានលុប។"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"យកចេញ"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"កម្មវិធីសន្សំថ្មគឺបើក"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"កម្មវិធីសន្សំថ្មបានបើក"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ការបន្ថយការប្រតិបត្តិ និងទិន្នន័យផ្ទៃខាងក្រោយ"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"បិទធាតុរក្សាថាមពលថ្ម"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"បិទកម្មវិធីសន្សំថ្ម"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> នឹងចាប់ផ្ដើមចាប់យកអ្វីៗគ្រប់យ៉ាងដែលបង្ហាញលើអេក្រង់របស់អ្នក។"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"កុំបង្ហាញម្ដងទៀត"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"សម្អាតទាំងអស់"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d នាទី</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"ការប្រើប្រាស់ថ្ម"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"កម្មវិធីសន្សំថ្មមិនអាចប្រើបានអំឡុងពេលសាកថ្មទេ"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"កម្មវិធីសន្សំថ្ម"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"កម្មវិធីសន្សំថ្មមិនអាចប្រើបានអំឡុងពេលសាកថ្មទេ"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"កម្មវិធីសន្សំថ្ម"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"កាត់បន្ថយប្រតិបត្តិការ និងទិន្នន័យផ្ទៃខាងក្រោយ"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"ប៊ូតុង <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 7ba785b..f4aad96 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"ಅಧಿಸೂಚನೆಗಳು"</string>
<string name="battery_low_title" msgid="6456385927409742437">"ಬ್ಯಾಟರಿ ಕಡಿಮೆ ಇದೆ"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> ಉಳಿದಿದೆ"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> ಉಳಿದಿದೆ. ಬ್ಯಾಟರಿ ಉಳಿತಾಯ ಆನ್ ಆಗಿದೆ."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> ಉಳಿದಿದೆ. ಬ್ಯಾಟರಿ ಉಳಿತಾಯ ಆನ್ ಆಗಿದೆ."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB ಚಾರ್ಜಿಂಗ್ ಬೆಂಬಲಿತವಾಗಿಲ್ಲ.\nಒದಗಿಸಿರುವ ಚಾರ್ಜರ್ ಮಾತ್ರ ಬಳಸಿ."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB ಚಾರ್ಜಿಂಗ್ ಬೆಂಬಲಿತವಾಗಿಲ್ಲ."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"ಒದಗಿಸಿರುವ ಚಾರ್ಜರ್ ಮಾತ್ರ ಬಳಸಿ."</string>
<string name="battery_low_why" msgid="4553600287639198111">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"ಬ್ಯಾಟರಿ ಉಳಿತಾಯವನ್ನು ಆನ್ ಮಾಡುವುದೇ?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಆನ್ ಮಾಡುವುದೇ?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"ಆನ್ ಮಾಡಿ"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"ಬ್ಯಾಟರಿ ಉಳಿತಾಯವನ್ನು ಆನ್ ಮಾಡಿ"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಆನ್ ಮಾಡಿ"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"ವೈ-ಫೈ"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"ಪರದೆಯನ್ನು ಸ್ವಯಂ-ತಿರುಗಿಸಿ"</string>
@@ -51,21 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"ಬ್ಲೂಟೂತ್ ವ್ಯಾಪ್ತಿ ತಲುಪಿದೆ"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ಇನ್ಪುಟ್ ವಿಧಾನಗಳನ್ನು ಹೊಂದಿಸು"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್"</string>
- <!-- no translation found for usb_device_permission_prompt (1825685909587559679) -->
- <skip />
- <!-- no translation found for usb_accessory_permission_prompt (2465531696941369047) -->
- <skip />
- <!-- no translation found for usb_device_confirm_prompt (7440562274256843905) -->
- <skip />
- <!-- no translation found for usb_accessory_confirm_prompt (4333670517539993561) -->
- <skip />
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ಗೆ ಪ್ರವೇಶಿಸಲು <xliff:g id="APPLICATION">%1$s</xliff:g> ಅನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ಗೆ ಪ್ರವೇಶಿಸಲು <xliff:g id="APPLICATION">%1$s</xliff:g> ಅನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ಅನ್ನು ನಿರ್ವಹಿಸಲು <xliff:g id="APPLICATION">%1$s</xliff:g> ಅನ್ನು ತೆರೆಯುವುದೇ?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ಅನ್ನು ನಿರ್ವಹಿಸಲು <xliff:g id="APPLICATION">%1$s</xliff:g> ಅನ್ನು ತೆರೆಯುವುದೇ?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ಆಪ್ಗಳು USB ಪರಿಕರದಲ್ಲಿ ಕಾರ್ಯನಿರ್ವಹಿಸುವುದಿಲ್ಲ. ಆ ಬಗ್ಗೆ <xliff:g id="URL">%1$s</xliff:g> ನಲ್ಲಿ ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB ಪರಿಕರ"</string>
<string name="label_view" msgid="6304565553218192990">"ವೀಕ್ಷಿಸು"</string>
- <!-- no translation found for always_use_device (4015357883336738417) -->
- <skip />
- <!-- no translation found for always_use_accessory (3257892669444535154) -->
- <skip />
+ <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ಸಂಪರ್ಕಗೊಂಡಾಗ ಯಾವಾಗಲೂ <xliff:g id="APPLICATION">%1$s</xliff:g> ಅನ್ನು ತೆರೆಯಿರಿ"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ಸಂಪರ್ಕಗೊಂಡಾಗ ಯಾವಾಗಲೂ <xliff:g id="APPLICATION">%1$s</xliff:g> ಅನ್ನು ತೆರೆಯಿರಿ"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB ಡೀಬಗ್ ಮಾಡುವಿಕೆಯನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"ಕಂಪ್ಯೂಟರ್ನ RSA ಕೀ ಫಿಂಗರ್ ಪ್ರಿಂಟ್ ಹೀಗಿದೆ :\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"ಈ ಕಂಪ್ಯೂಟರ್ನಿಂದ ಯಾವಾಗಲೂ ಅನುಮತಿಸಿ"</string>
@@ -249,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"ಡೇಟಾ ಬಳಕೆಯು ನೀವು ಹೊಂದಿಸಿರುವ ಮಿತಿಯನ್ನು ತಲುಪಿದೆ. ಹೀಗಾಗಿ ನೀವು ಈಗ ಮೊಬೈಲ್ ಡೇಟಾ ಬಳಸುತ್ತಿಲ್ಲ.\n\nನೀವು ಮುಂದುವರಿದರೆ, ಡೇಟಾ ಬಳಕೆಗೆ ಶುಲ್ಕ ತೆರಬೇಕಾಗಬಹುದು."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ಮುಂದುವರಿಸು"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವಿಲ್ಲ"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ವೈ-ಫೈ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS ಗಾಗಿ ಹುಡುಕಲಾಗುತ್ತಿದೆ"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"ಸ್ಥಾನವನ್ನು GPS ಮೂಲಕ ಹೊಂದಿಸಲಾಗಿದೆ"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"ಸ್ಥಳ ವಿನಂತಿಗಳು ಸಕ್ರಿಯವಾಗಿವೆ"</string>
@@ -407,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕುವುದೇ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"ಈ ಬಳಕೆದಾರರ ಎಲ್ಲಾ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುವುದು."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"ತೆಗೆದುಹಾಕಿ"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"ಬ್ಯಾಟರಿ ರಕ್ಷಕ ಆನ್ ಆಗಿದೆ"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"ಬ್ಯಾಟರಿ ರಕ್ಷಕ ಆನ್ ಆಗಿದೆ"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ಕಾರ್ಯಕ್ಷಮತೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಡೇಟಾವನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ಬ್ಯಾಟರಿ ಉಳಿತಾಯವನ್ನು ಆಫ್ ಮಾಡಿ"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಆಫ್ ಮಾಡಿ"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"ನಿಮ್ಮ ಪರದೆಯ ಮೇಲೆ ಪ್ರದರ್ಶಿಸಲಾಗುವ ಎಲ್ಲವನ್ನೂ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ಯು ಸೆರೆಹಿಡಿಯಲು ಪ್ರಾರಂಭಿಸುತ್ತದೆ."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"ಮತ್ತೊಮ್ಮೆ ತೋರಿಸದಿರು"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸು"</string>
@@ -588,8 +580,8 @@
<item quantity="other">%d ನಿಮಿಷಗಳು</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"ಬ್ಯಾಟರಿ ಬಳಕೆ"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"ಚಾರ್ಜಿಂಗ್ ಸಮಯದಲ್ಲಿ ಬ್ಯಾಟರಿ ಸೇವರ್ ಲಭ್ಯವಿರುವುದಿಲ್ಲ"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"ಬ್ಯಾಟರಿ ಸೇವರ್"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ಚಾರ್ಜಿಂಗ್ ಸಮಯದಲ್ಲಿ ಬ್ಯಾಟರಿ ಸೇವರ್ ಲಭ್ಯವಿರುವುದಿಲ್ಲ"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"ಬ್ಯಾಟರಿ ಸೇವರ್"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"ಕಾರ್ಯಕ್ಷಮತೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಡೇಟಾವನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> ಬಟನ್"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-ko/config.xml b/packages/SystemUI/res/values-ko/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-ko/config.xml
+++ b/packages/SystemUI/res/values-ko/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index ddc201b..43d171c 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"알림"</string>
<string name="battery_low_title" msgid="6456385927409742437">"배터리 부족"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> 남았습니다."</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> 남았습니다. 배터리 절약 기능을 사용 중입니다."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> 남았습니다. 배터리 세이버를 사용 중입니다."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB 충전이 지원되지 않습니다.\n제공된 충전기만 사용하세요."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB 충전은 지원되지 않습니다."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"제공된 충전기만 사용하세요."</string>
<string name="battery_low_why" msgid="4553600287639198111">"설정"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"배터리 절약 기능을 사용하시겠습니까?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"배터리 세이버를 사용 설정하시겠습니까?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"사용"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"배터리 절약 기능 사용"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"배터리 세이버 사용 설정"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"설정"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"자동 화면 회전"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"블루투스 테더링됨"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"입력 방법 설정"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"물리적 키보드"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"<xliff:g id="APPLICATION">%1$s</xliff:g> 앱이 USB 기기에 액세스하도록 허용하시겠습니까?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"<xliff:g id="APPLICATION">%1$s</xliff:g> 앱이 USB 액세서리에 액세스하도록 허용하시겠습니까?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"USB 기기가 연결될 때 <xliff:g id="ACTIVITY">%1$s</xliff:g>(을)를 여시겠습니까?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"USB 액세서리가 연결될 때 <xliff:g id="ACTIVITY">%1$s</xliff:g>(을)를 여시겠습니까?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> 앱이 <xliff:g id="USB_DEVICE">%2$s</xliff:g>에 액세스하도록 허용하시겠습니까?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> 앱이 <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>에 액세스하도록 허용하시겠습니까?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="APPLICATION">%1$s</xliff:g> 앱을 열어 <xliff:g id="USB_DEVICE">%2$s</xliff:g>을(를) 처리하시겠습니까?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="APPLICATION">%1$s</xliff:g> 앱을 열어 <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>을(를) 처리하시겠습니까?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"이 USB와 호환되는 설치 앱이 없습니다. <xliff:g id="URL">%1$s</xliff:g>에서 세부정보를 참조하세요."</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB 액세서리"</string>
<string name="label_view" msgid="6304565553218192990">"보기"</string>
- <string name="always_use_device" msgid="1450287437017315906">"이 USB 기기에 기본값으로 사용"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"이 USB 액세서리에 기본값으로 사용"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>이(가) 연결되면 항상 <xliff:g id="APPLICATION">%1$s</xliff:g> 열기"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>이(가) 연결되면 항상 <xliff:g id="APPLICATION">%1$s</xliff:g> 열기"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB 디버깅을 허용하시겠습니까?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"컴퓨터 RSA 키 지문:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"이 컴퓨터에서 항상 허용"</string>
@@ -245,8 +245,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"데이터 사용 중지됨"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"설정한 데이터 한도에 도달했습니다. 더 이상 모바일 데이터를 사용하지 않습니다.\n\n계속하면 데이터 사용량에 따라 요금이 부과될 수 있습니다."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"재개"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"인터넷에 연결되지 않음"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 연결됨"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS 검색 중"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS에서 위치 설정"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"위치 요청 있음"</string>
@@ -403,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"사용자를 삭제할까요?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"이 사용자의 모든 앱과 데이터가 삭제됩니다."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"삭제"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"배터리 세이버 사용 중"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"배터리 세이버 사용 중"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"성능 및 백그라운드 데이터를 줄입니다."</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"배터리 절약 기능 사용 중지"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"배터리 세이버 사용 중지"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>에서 화면에 표시된 모든 것을 캡처하기 시작합니다."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"다시 표시 안함"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"모두 지우기"</string>
@@ -584,8 +582,8 @@
<item quantity="one">%d분</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"배터리 사용량"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"충전 중에는 배터리 세이버를 사용할 수 없습니다."</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"배터리 세이버"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"충전하는 동안 배터리 세이버는 사용할 수 없습니다."</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"배터리 세이버"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"성능 및 백그라운드 데이터를 줄입니다."</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> 버튼"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-ky/config.xml b/packages/SystemUI/res/values-ky/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-ky/config.xml
+++ b/packages/SystemUI/res/values-ky/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index cbd3ec02..375d70d 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Эскертмелер"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Батареянын кубаты аз"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> калды"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> калды. Батареянын кубатын үнөмдөгүч күйүк."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> калды. Батареяны үнөмдөгүч режими күйүк."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB менен кубаттоо колдоого алынбайт.\nБерилген заряддагычты гана колдонуңуз."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB аркылуу кубаттоого болбойт."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Коштолгон кубаттагычты гана колдонуңуз."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Жөндөөлөр"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Батареянын кубатын үнөмдөгүч күйгүзүлсүнбү?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Батареяны үнөмдөгүч режими күйгүзүлсүнбү?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Күйгүзүү"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Батареянын кубатын үнөмдөгүчтү иштетүү"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Батареяны үнөмдөгүч режимин күйгүзүү"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Жөндөөлөр"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi‑Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Экрандын авто-айлануусу"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth жалгашты"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Киргизүү ыкмасын тууралоо"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Аппараттык тергич"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"<xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна USB түзмөккө жеткенге уруксат берилсинби?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"<xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна USB аксессуарына жеткенге уруксат берилсинби?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"USB түзмөк туташканда <xliff:g id="ACTIVITY">%1$s</xliff:g> ачылсынбы?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"USB шайманы туташканда <xliff:g id="ACTIVITY">%1$s</xliff:g> ачылсынбы?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосу <xliff:g id="USB_DEVICE">%2$s</xliff:g> түзмөгүн колдоно берсинби?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосу <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> кабелин колдоно берсинби?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> түзмөгүнө туташуу үчүн <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосу ачылсынбы?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> кабелине туташуу үчүн <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосу ачылсынбы?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Эч бир орнотулган колдонмо USB аксессуар м-н иштебейт. Кенен маалыматтар: <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB шайманы"</string>
<string name="label_view" msgid="6304565553218192990">"Карап көрүү"</string>
- <string name="always_use_device" msgid="1450287437017315906">"USB түзмөгү үчүн демейки боюнча колдонулсун"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Бул USB шайманы үчүн демейки боюнча колдонулсун"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> туташып турганда, <xliff:g id="APPLICATION">%1$s</xliff:g> ар дайым ачык болун"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> туташып турганда, <xliff:g id="APPLICATION">%1$s</xliff:g> ар дайым ачык болсун"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB аркылуу жөндөөгө уруксат берилсинби?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Компүтердин RSA ачкычынын контролдук суммасы:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Бул компүтерден дайыма уруксат берилсин"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Дайындар тындырылды"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Трафик сиз койгон чекке жетти. Эми мобилдик Интернетти колдоно албайсыз.\n\nЭгер улантсаңыз, дайындарды өткөрүү үчүн акы алынышы мүмкүн."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Улантуу"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланыш жок"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi байланышта"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS издөө"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS боюнча аныкталган жайгашуу"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Жайгаштыруу талаптары иштелүүдө"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Колдонуучу алынып салынсынбы?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Бул колдонуучунун бардык колдонмолору жана дайындары жок кылынат."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Алып салуу"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Батареяны үнөмдөгүч күйгүзүлдү"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Батареяны үнөмдөгүч режими күйүк"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Иштин майнаптуулугун начарлатып, фондук дайындарды чектейт"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Батареянын кубатын үнөмдөгүчтү өчүрүп коюу"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Батареяны үнөмдөгүч режимин өчүрүү"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> экранга чыккан нерсенин баарын сүрөткө тарта баштайт."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Экинчи көрсөтүлбөсүн"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Бардыгын тазалап салуу"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d мүнөт</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Батарея колдонулушу"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Батареяны үнөмдөгүч түзмөк кубатталып жатканда иштебейт"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Батареяны үнөмдөгүч"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Батареяны үнөмдөгүч түзмөк кубатталып жатканда иштебейт"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Батареяны үнөмдөгүч"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Иштин майнаптуулугун начарлатып, фондук дайындарды чектейт"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> баскычы"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Башкы бет"</string>
diff --git a/packages/SystemUI/res/values-lo/config.xml b/packages/SystemUI/res/values-lo/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-lo/config.xml
+++ b/packages/SystemUI/res/values-lo/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 941ef71..064609e 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"ການແຈ້ງເຕືອນ"</string>
<string name="battery_low_title" msgid="6456385927409742437">"ແບັດເຕີຣີເຫຼືອໜ້ອຍ"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"ຍັງເຫຼືອ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"ຍັງເຫຼືອ <xliff:g id="PERCENTAGE">%s</xliff:g>. ການປະຢັດແບັດເຕີຣີໄດ້ຖືກເປີດໃຊ້ແລ້ວ."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"ຍັງເຫຼືອ <xliff:g id="PERCENTAGE">%s</xliff:g>. ເປີດໃຊ້ຕົວປະຢັດແບັດເຕີຣີແລ້ວ."</string>
<string name="invalid_charger" msgid="4549105996740522523">"ບໍ່ຮອງຮັບການສາກໄຟດ້ວຍ USB.\nຕ້ອງໃຊ້ສະເພາະເຄື່ອງສາກທີ່ແຖມມານຳເທົ່ານັ້ນ."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"ບໍ່ຮອງຮັບການສາກຜ່ານ USB."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"ໃຊ້ສະເພາະສາຍສາກທີ່ມາກັບເຄື່ອງ."</string>
<string name="battery_low_why" msgid="4553600287639198111">"ການຕັ້ງຄ່າ"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"ເປີດໃຊ້ການປະຢັດແບັດເຕີຣີບໍ?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"ເປີດໃຊ້ຕົວປະຢັດແບັດເຕີຣີບໍ?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"ເປີດໃຊ້"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"ເປີດໃຊ້ໂຕປະຢັດແບັດເຕີຣີ"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"ເປີດໃຊ້ຕົວປະຢັດແບັດເຕີຣີ"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ການຕັ້ງຄ່າ"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"ໝຸນໜ້າຈໍອັດຕະໂນມັດ"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"ປ່ອຍສັນຍານຜ່ານ Bluetooth ແລ້ວ"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ຕັ້ງຄ່າວິທີການປ້ອນຂໍ້ມູນ"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"ແປ້ນພິມແທ້"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"ອະນຸຍາດໃຫ້ແອັບຯ <xliff:g id="APPLICATION">%1$s</xliff:g> ເຂົ້າເຖິງອຸປະກອນ USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"ອະນຸຍາດໃຫ້ແອັບຯ <xliff:g id="APPLICATION">%1$s</xliff:g> ເຂົ້າເຖິງອຸປະກອນພ່ວງ USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"ເປີດ <xliff:g id="ACTIVITY">%1$s</xliff:g> ເມື່ອເຊື່ອມຕໍ່ກັບອຸປະກອນ USB ນີ້ຫຼືບໍ່?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"ເປີດ <xliff:g id="ACTIVITY">%1$s</xliff:g> ເມື່ອມີການເຊື່ອມຕໍ່ກັບອຸປະກອນເສີມ USB ນີ້ຫຼືບໍ່?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"ອະນຸຍາດໃຫ້ <xliff:g id="APPLICATION">%1$s</xliff:g> ເຂົ້າເຖິງ <xliff:g id="USB_DEVICE">%2$s</xliff:g> ໄດ້ບໍ?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"ອະນຸຍາດໃຫ້ <xliff:g id="APPLICATION">%1$s</xliff:g> ເຂົ້າເຖິງ <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ໄດ້ບໍ?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"ເປີດ <xliff:g id="APPLICATION">%1$s</xliff:g> ເພື່ອໃຊ້ກັບ <xliff:g id="USB_DEVICE">%2$s</xliff:g> ບໍ?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"ເປີດ <xliff:g id="APPLICATION">%1$s</xliff:g> ເພື່ອໃຊ້ກັບ <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ບໍ?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ບໍ່ມີແອັບຯໃດທີ່ຕິດຕັ້ງໄປແລ້ວ ສາມາດເຮັດວຽກຮ່ວມກັບອຸປະກອນເສີມ USB ນີ້ໄດ້. ສຶກສາເພີ່ມເຕີມກ່ຽວກັບອຸປະກອນເສີມນີ້ທີ່ <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"ອຸປະກອນເສີມ USB"</string>
<string name="label_view" msgid="6304565553218192990">"ເບິ່ງ"</string>
- <string name="always_use_device" msgid="1450287437017315906">"ໃຊ້ເປັນຄ່າເລີ່ມຕົ້ນສຳລັບອຸປະກອນ USB ນີ້"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"ໃຊ້ຄ່າເລີ່ມຕົ້ນສຳລັບອຸປະກອນເສີມ USB ນີ້."</string>
+ <string name="always_use_device" msgid="4015357883336738417">"ເປີດ <xliff:g id="APPLICATION">%1$s</xliff:g> ທຸກເທື່ອທີ່ເຊື່ອມຕໍ່ <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"ເປີດ <xliff:g id="APPLICATION">%1$s</xliff:g> ທຸກເທື່ອທີ່ເຊື່ອມຕໍ່ <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"ອະນຸຍາດການດີບັ໊ກຜ່ານ USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"ລາຍນິ້ມື RSA ຂອງຄອມພິວເຕີແມ່ນ:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"ອະນຸຍາດຈາກຄອມພິວເຕີນີ້ຕະຫຼອດ"</string>
@@ -180,7 +180,6 @@
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ທຸກແອັບພລິເຄຊັນບໍ່ດົນມານີ້ຖືກປ່ອຍໄປ."</string>
<string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"ເປີດຂໍ້ມູນແອັບພລິເຄຊັນ <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"ກຳລັງເປີດ <xliff:g id="APP">%s</xliff:g>."</string>
- <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"ປິດການແຈ້ງເຕືອນແລ້ວ."</string>
<string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"ໜ້າຈໍແຈ້ງເຕືອນ."</string>
<string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"ການຕັ້ງຄ່າດ່ວນ."</string>
@@ -244,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ຂໍ້ມູນຢຸດຊົ່ວຄາວແລ້ວ"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"ທ່ານໃຊ້ອິນເຕີເນັດຮອດຈຳນວນທີ່ທ່ານຈຳກັດປະລິມານໄວ້ແລ້ວ. ທ່ານຈະບໍ່ນຳໃຊ້ການເຊື່ອມຕໍ່ຜ່ານເຄືອຂ່າຍມືຖືອີກຕໍ່ໄປ.\n\nຫາກທ່ານສືບຕໍ່ໃຊ້ໄປອີກ, ທ່ານອາດຖືກຮຽກເກັບເງິນຄ່າບໍລິການໄດ້."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ເລີ່ມຕໍ່"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ເຊື່ອມຕໍ່ Wi--Fi ແລ້ວ"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"ກຳລັງຊອກຫາ GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"ສະຖານທີ່ກຳນົດໂດຍ GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"ການຮ້ອງຂໍສະຖານທີ່ທີ່ເຮັດວຽກຢູ່"</string>
@@ -343,8 +340,6 @@
<string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Split screen to the top"</string>
<string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Split screen to the left"</string>
<string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Split screen to the right"</string>
- <string-array name="recents_blacklist_array">
- </string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"ສາກເຕັມແລ້ວ."</string>
<string name="expanded_header_battery_charging" msgid="205623198487189724">"ກຳລັງສາກໄຟ"</string>
<string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> ຈຶ່ງຈະເຕັມ"</string>
@@ -404,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"ລຶບຜູ້ໃຊ້ອອກບໍ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"ທຸກແອັບ ແລະ ຂໍ້ມູນຂອງຜູ້ໃຊ້ນີ້ຈະຖືກລຶບ."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"ເອົາອອກ"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"ເປີດໃຊ້ໂຕປະຢັດແບັດເຕີຣີແລ້ວ"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"ຕົວປະຢັດແບັດເຕີຣີເປີດຢູ່"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ຫຼຸດປະສິທິພາບແລະການນຳໃຊ້ຂໍ້ມູນພື້ນຫຼັງ"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ປິດໂຕປະຢັດແບັດເຕີຣີ"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"ປິດຕົວປະຢັດແບັດເຕີຣີ"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ຈະເລີ່ມບັນທຶກທຸກຢ່າງທີ່ສະແດງຜົນໃນໜ້າຈໍທ່ານ."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"ບໍ່ຕ້ອງສະແດງອີກ"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"ລຶບລ້າງທັງໝົດ"</string>
@@ -585,8 +580,8 @@
<item quantity="one">%d ນາທີ</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"ການໃຊ້ແບັດເຕີຣີ"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"ບໍ່ສາມາດໃຊ້ຕົວປະຢັດແບັດເຕີຣີໃນຂະນະທີ່ກຳລັງສາກໄຟໄດ້"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"ຕົວປະຢັດແບັດເຕີຣີ"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ຕົວປະຢັດແບັດເຕີຣີບໍ່ມີໃຫ້ນຳໃຊ້ໃນລະຫວ່າງການສາກ"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"ຕົວປະຢັດແບັດເຕີຣີ"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"ຫຼຸດປະສິທິພາບການໃຊ້ງານ ແລະ ຂໍ້ມູນພື້ນຫຼັງ"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"ປຸ່ມ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-lt/config.xml b/packages/SystemUI/res/values-lt/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-lt/config.xml
+++ b/packages/SystemUI/res/values-lt/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 774a123..f44b930 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -36,14 +36,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Pranešimai"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Akumuliatorius senka"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Liko <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Liko <xliff:g id="PERCENTAGE">%s</xliff:g>. Akumuliatoriaus tausojimo programa įjungta."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Liko <xliff:g id="PERCENTAGE">%s</xliff:g>. Akumuliatoriaus tausojimo priemonė įjungta."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB krovimas nepalaikomas.\nNaudokite tik pateiktą įkroviklį."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB įkrovimas nepalaikomas."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Naudokite tik pateiktą kroviklį."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Nustatymai"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Įjungti Akumuliatoriaus tausojimo priemonę?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Įjungti Akumuliatoriaus tausojimo priemonę?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Įjungti"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Įj. Akum. tausojimo priemonę"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Įjungti Akumuliatoriaus tausojimo priemonę"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nustatymai"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatiškai sukti ekraną"</string>
@@ -53,15 +53,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"„Bluetooth“ susieta"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Nustatyti įvesties metodus"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fizinė klaviatūra"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Leisti programai „<xliff:g id="APPLICATION">%1$s</xliff:g>“ pasiekti USB įrenginį?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Leisti programai „<xliff:g id="APPLICATION">%1$s</xliff:g>“ pasiekti USB priedą?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Atidaryti <xliff:g id="ACTIVITY">%1$s</xliff:g>, kai prijungtas šis USB įrenginys?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Atidaryti <xliff:g id="ACTIVITY">%1$s</xliff:g>, kai prijungtas šis USB priedas?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Leisti „<xliff:g id="APPLICATION">%1$s</xliff:g>“ pasiekti įrenginį (<xliff:g id="USB_DEVICE">%2$s</xliff:g>)?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Leisti „<xliff:g id="APPLICATION">%1$s</xliff:g>“ pasiekti įrenginį (<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>)?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Atidaryti „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kad būtų galima tvarkyti įrenginį (<xliff:g id="USB_DEVICE">%2$s</xliff:g>)?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Atidaryti „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kad būtų galima tvarkyti įrenginį (<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>)?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Su šiuo USB priedu neveiks jokios įdieg. pr. Suž. daugiau apie šį priedą adresu <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB reikmuo"</string>
<string name="label_view" msgid="6304565553218192990">"Žiūrėti"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Šiam USB įreng. naudoti pagal numat. nustatymus"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Šiam USB priedui naudoti pagal numat. nustatymus"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Visada atidaryti „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kai prijungiamas (-a) <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Visada atidaryti „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kai prijungiamas (-a) <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Leisti USB derinimą?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Šio kompiuterio RSA rakto kontrolinis kodas yra:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Visada leisti iš šio kompiuterio"</string>
@@ -245,8 +245,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Duomenys pristabdyti"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Pasiektas nustatytas duomenų limitas. Nebenaudojate mobiliojo ryšio duomenų.\n\nJei tęsite, gali būti taikomi duomenų naudojimo mokesčiai."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Atnaujinti"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nėra interneto ryš."</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Prisij. prie „Wi-Fi“"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Ieškoma GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS nustatyta vieta"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Vietovės užklausos aktyvios"</string>
@@ -405,9 +403,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Pašalinti naudotoją?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Bus ištrinti visi šio naudotojo duomenys ir programos."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Pašalinti"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Akumuliatoriaus tausojimo priemonė įjungta"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Akumuliatoriaus tausojimo priemonė įjungta"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Sumažinamas našumas ir foninių duomenų naudojimas"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Išjungti Akumuliatoriaus tausojimo priemonę"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Išjungti Akumuliatoriaus tausojimo priemonę"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"„<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“ pradės fiksuoti viską, kas rodoma jūsų ekrane."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Daugiau neberodyti"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Viską išvalyti"</string>
@@ -594,8 +592,8 @@
<item quantity="other">%d minučių</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Akum. energ. vartoj."</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Akumuliatoriaus tausojimo priemonė nepasiekiama įkraunant"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Akumuliatoriaus tausojimo priemonė"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Akumuliatoriaus tausojimo priemonė nepasiekiama įkraunant"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Akumuliatoriaus tausojimo priemonė"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Sumažinamas našumas ir foninių duomenų naudojimas"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Mygtukas <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Pagrindinis"</string>
diff --git a/packages/SystemUI/res/values-lv/config.xml b/packages/SystemUI/res/values-lv/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-lv/config.xml
+++ b/packages/SystemUI/res/values-lv/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index dfbd0d2..8c117b3 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -35,14 +35,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Paziņojumi"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Zems akumulatora enerģijas līmenis"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Atlikuši <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Atlikuši <xliff:g id="PERCENTAGE">%s</xliff:g>. Ir ieslēgts akumulatora jaudas taupīšanas režīms."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Atlikuši <xliff:g id="PERCENTAGE">%s</xliff:g>. Ir ieslēgts akumulatora jaudas taupīšanas režīms."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB lādēšana netiek atbalstīta.\nIzmantojiet tikai komplektā iekļauto lādētāju."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB uzlāde netiek atbalstīta."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Izmantojiet tikai komplektā iekļauto lādētāju."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Iestatījumi"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Vai ieslēgt akumulatora jaudas taupīšanu?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Vai ieslēgt akumulatora jaudas taupīšanas režīmu?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Ieslēgt"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Ieslēgt akumulatora jaudas taupīšanu"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Ieslēgt akumulatora jaudas taupīšanas režīmu"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Iestatījumi"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automātiska ekrāna pagriešana"</string>
@@ -52,15 +52,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth piesaiste"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Iestatīt ievades metodes"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fiziskā tastatūra"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Vai ļaut lietotnei <xliff:g id="APPLICATION">%1$s</xliff:g> piekļūt šai USB ierīcei?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vai ļaut lietotnei <xliff:g id="APPLICATION">%1$s</xliff:g> piekļūt šim USB piederumam?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vai atvērt darbību <xliff:g id="ACTIVITY">%1$s</xliff:g>, kad tiek pievienota šī USB ierīce?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Vai atvērt darbību <xliff:g id="ACTIVITY">%1$s</xliff:g>, kad tiek pievienots šis USB piederums?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Vai atļaut lietotnei <xliff:g id="APPLICATION">%1$s</xliff:g> piekļūt šai ierīcei: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Vai atļaut lietotnei <xliff:g id="APPLICATION">%1$s</xliff:g> piekļūt šim piederumam: <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Vai atvērt lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, lai izmantotu šo ierīci: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Vai atvērt lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, lai izmantotu šo piederumu: <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Neviena no inst. liet. nedarb. ar šo USB pied. Uzz. vairāk par šo pied. vietnē <xliff:g id="URL">%1$s</xliff:g>."</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB piederums"</string>
<string name="label_view" msgid="6304565553218192990">"Skatīt"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Pēc noklusējuma izmantot šai USB ierīcei"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Pēc noklusējuma izmantot šim USB piederumam"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Vienmēr atvērt lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kad ir pievienota <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Vienmēr atvērt lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kad ir pievienots <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Vai atļaut USB atkļūdošanu?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Datora RSA atslēgas ciparfails: \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Vienmēr atļaut no šī datora"</string>
@@ -244,8 +244,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datu lietojums ir apturēts"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Ir sasniegts jūsu iestatītais datu ierobežojums. Jūs vairs neizmantojat mobilos datus.\n\nJa atsāksiet, var tikt piemērota maksa par datu lietojumu."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Atsākt"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nav interneta sav."</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Izv. sav. ar Wi-Fi"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Notiek GPS meklēšana..."</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS iestatītā atrašanās vieta"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Aktīvi atrašanās vietu pieprasījumi"</string>
@@ -403,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Vai noņemt lietotāju?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Tiks dzēstas visas šī lietotāja lietotnes un dati."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Noņemt"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Ieslēgts akumulatora enerģijas taupīšanas režīms"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Akumulatora jaudas taupīšanas režīms ir ieslēgts"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Samazina veiktspēju un fona datus"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Izslēgt akumulatora jaudas taupīšanu"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Izslēgt akumulatora jaudas taupīšanas režīmu"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sāks uzņemt visu, kas tiks rādīts jūsu ekrānā."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Vairs nerādīt"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Dzēst visu"</string>
@@ -588,8 +586,8 @@
<item quantity="other">%d minūtes</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Akumulatora lietojums"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Akumulatora jaudas taupīšanas režīms nav pieejams uzlādes laikā."</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Akumulatora jaudas taupīšanas režīms"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Akumulatora jaudas taupīšanas režīms uzlādes laikā nav pieejams."</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Akumulatora jaudas taupīšanas režīms"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Samazina veiktspēju un fona datus."</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Poga <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Sākumvietas taustiņš"</string>
diff --git a/packages/SystemUI/res/values-mk/config.xml b/packages/SystemUI/res/values-mk/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-mk/config.xml
+++ b/packages/SystemUI/res/values-mk/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index d62775c..195ddec 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Известувања"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Батеријата е слаба"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Преостануваат <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Преостануваат <xliff:g id="PERCENTAGE">%s</xliff:g>. Вклучен е штедачот на батерија."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Преостануваат <xliff:g id="PERCENTAGE">%s</xliff:g>. Штедачот на батерија е вклучен."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Полначот на USB меморијата не е поддржан.\nКористете го само полначот доставен со уредот."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Полнењето преку USB не е поддржано."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Користете го само доставениот полнач."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Поставки"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Дали да се вклучи штедачот на батерија?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Да се вклучи штедачот на батерија?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Вклучи"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Вклучете го штедачот на батерија"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Да се вклучи штедачот на батерија?"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Поставки"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Автоматско ротирање на екранот"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Поврзан е Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Постави методи на внес."</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Физичка тастатура"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Дозволи апликацијата <xliff:g id="APPLICATION">%1$s</xliff:g> да пристапи кон USB уредот?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Дозволи апликацијата <xliff:g id="APPLICATION">%1$s</xliff:g> да пристапи кон USB додатокот?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Отвори <xliff:g id="ACTIVITY">%1$s</xliff:g> кога е поврзан овој USB уред?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Отвори <xliff:g id="ACTIVITY">%1$s</xliff:g> кога е поврзан овој USB додаток?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Ќе дозволите <xliff:g id="APPLICATION">%1$s</xliff:g> да пристапува до <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Ќе дозволите <xliff:g id="APPLICATION">%1$s</xliff:g> да пристапува до <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Да се отвори <xliff:g id="APPLICATION">%1$s</xliff:g> за да управува со <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Да се отвори <xliff:g id="APPLICATION">%1$s</xliff:g> за да управува со <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Нема инсталирано апликации што работат со овој USB додаток. Дознајте повеќе за овој додаток на <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB додаток"</string>
<string name="label_view" msgid="6304565553218192990">"Прикажи"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Користи го стандардно за овој USB уред"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Користи го стандардно за овој приклучок за USB"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Секогаш отворај ја <xliff:g id="APPLICATION">%1$s</xliff:g> кога е поврзан <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Секогаш отворај ја <xliff:g id="APPLICATION">%1$s</xliff:g> кога е поврзан <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Овозможи отстранување грешки на USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Клучниот отпечаток на RSA на компјутерот е:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Секогаш дозволувај од овој компјутер"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Податоците се паузирани"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Го достигнавте ограничувањето за мобилен сообраќај што сте го поставиле. Веќе не користите мобилен интернет.\n\nДоколку продолжите, ќе ви биде наплатено за потрошениот сообраќај."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Продолжи"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нема интернет"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Поврзано на Wi-Fi"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Се пребарува за GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Локацијата е поставена со GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Активни барања за локација"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Да се отстрани корисникот?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Сите апликации и податоци од овој корисник ќе се избришат."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Отстрани"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Штедачот на батерија е вклучен"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Штедачот на батерија е вклучен"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Ја намалува изведбата и податоците во заднина"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Исклучете го штедачот на батерија"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Исклучете го штедачот на батерија"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ќе започне да презема сѐ што се прикажува на вашиот екран."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Не покажувај повторно"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Исчисти сè"</string>
@@ -582,8 +580,8 @@
<item quantity="other">%d минути</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Користење батерија"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Штедачот на батерија не е достапен при полнење"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Штедач на батерија"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Штедачот на батерија не е достапен при полнење"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Штедач на батерија"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Ја намалува изведбата и податоците во заднина"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Копче <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home-копче"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 5522e51..3eb67df 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"അറിയിപ്പുകൾ"</string>
<string name="battery_low_title" msgid="6456385927409742437">"ബാറ്ററി കുറവാണ്"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> ശേഷിക്കുന്നു"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> ശേഷിക്കുന്നു. ബാറ്ററി ലാഭിക്കൽ ഓണാണ്."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> ശേഷിക്കുന്നു. ബാറ്ററി ലാഭിക്കൽ ഓണാണ്."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB ചാർജ്ജുചെയ്യൽ പിന്തുണയ്ക്കുന്നില്ല.\nഅതിന്റെ അനുബന്ധ ചാർജ്ജർ മാത്രം ഉപയോഗിക്കുക."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB ചാർജ്ജുചെയ്യൽ പിന്തുണച്ചില്ല."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"വിതരണം ചെയ്ത ചാർജ്ജർ മാത്രം ഉപയോഗിക്കുക."</string>
<string name="battery_low_why" msgid="4553600287639198111">"ക്രമീകരണം"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"ബാറ്ററി ലാഭിക്കൽ ഓണാക്കണോ?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"ബാറ്ററി ലാഭിക്കൽ ഓണാക്കണോ?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"ഓൺ ചെയ്യുക"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"ബാറ്ററി ലാഭിക്കൽ ഓണാക്കുക"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"ബാറ്ററി ലാഭിക്കൽ ഓണാക്കുക"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ക്രമീകരണം"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"വൈഫൈ"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"സ്ക്രീൻ സ്വയമേ തിരിക്കുക"</string>
@@ -51,21 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"ബ്ലൂടൂത്ത് ടെതർ ചെയ്തു"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ടൈപ്പുചെയ്യൽ രീതികൾ സജ്ജീകരിക്കുക"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"ഫിസിക്കൽ കീബോർഡ്"</string>
- <!-- no translation found for usb_device_permission_prompt (1825685909587559679) -->
- <skip />
- <!-- no translation found for usb_accessory_permission_prompt (2465531696941369047) -->
- <skip />
- <!-- no translation found for usb_device_confirm_prompt (7440562274256843905) -->
- <skip />
- <!-- no translation found for usb_accessory_confirm_prompt (4333670517539993561) -->
- <skip />
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ആക്സസ് ചെയ്യാൻ <xliff:g id="APPLICATION">%1$s</xliff:g>-നെ അനുവദിക്കണോ?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ആക്സസ് ചെയ്യാൻ <xliff:g id="APPLICATION">%1$s</xliff:g>-നെ അനുവദിക്കണോ?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> കൈകാര്യം ചെയ്യാൻ <xliff:g id="APPLICATION">%1$s</xliff:g> തുറക്കണോ?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> കൈകാര്യം ചെയ്യാൻ <xliff:g id="APPLICATION">%1$s</xliff:g> തുറക്കണോ?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ഈ USB ആക്സസ്സറിയിൽ ഇൻസ്റ്റാളുചെയ്തവയൊന്നും പ്രവർത്തിക്കുന്നില്ല. <xliff:g id="URL">%1$s</xliff:g>-ൽ ഇതേക്കുറിച്ച് കൂടുതലറിയുക"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB ആക്സസ്സറി"</string>
<string name="label_view" msgid="6304565553218192990">"കാണുക"</string>
- <!-- no translation found for always_use_device (4015357883336738417) -->
- <skip />
- <!-- no translation found for always_use_accessory (3257892669444535154) -->
- <skip />
+ <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> കണക്റ്റ് ചെയ്തിരിക്കുമ്പോൾ എപ്പോഴും <xliff:g id="APPLICATION">%1$s</xliff:g> തുറക്കൂ"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> കണക്റ്റ് ചെയ്തിരിക്കുമ്പോൾ എപ്പോഴും <xliff:g id="APPLICATION">%1$s</xliff:g> തുറക്കൂ"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB ഡീബഗ്ഗിംഗ് അനുവദിക്കണോ?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"ഈ കമ്പ്യൂട്ടറിന്റെ RSA കീ ഫിംഗർപ്രിന്റ് ഇതാണ്:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"ഈ കമ്പ്യൂട്ടറിൽ നിന്ന് എല്ലായ്പ്പോഴും അനുവദിക്കുക"</string>
@@ -249,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"നിങ്ങൾ സജ്ജമാക്കിയ ഡാറ്റ പരിധി എത്തിക്കഴിഞ്ഞു. ഇനിയങ്ങോട്ട് നിങ്ങൾക്ക് മൊബൈൽ ഡാറ്റ ഉപയോഗിക്കാൻ സാധിക്കുകയില്ല.\n\nതുടരുകയാണെങ്കിൽ, ഡാറ്റാ ഉപയോഗത്തിന് നിരക്കുകൾ ബാധകമായേക്കാം."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"പുനരാരംഭിക്കുക"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ഇന്റർനെറ്റ് കണക്ഷൻ ഇല്ല"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"വൈഫൈ കണക്റ്റുചെയ്തു"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS-നായി തിരയുന്നു"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"ലൊക്കേഷൻ സജ്ജീകരിച്ചത് GPS ആണ്"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"ലൊക്കേഷൻ അഭ്യർത്ഥനകൾ സജീവമാണ്"</string>
@@ -407,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"ഉപയോക്താവിനെ ഇല്ലാതാക്കണോ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"ഈ ഉപയോക്താവിന്റെ എല്ലാ ആപ്സും ഡാറ്റയും ഇല്ലാതാക്കും."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"നീക്കംചെയ്യുക"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"ബാറ്ററി ലാഭിക്കൽ ഓണാണ്"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"ബാറ്ററി ലാഭിക്കൽ ഓണാണ്"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"പ്രവർത്തനവും പശ്ചാത്തല ഡാറ്റയും കുറയ്ക്കുന്നു"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ബാറ്ററി ലാഭിക്കൽ ഓഫാക്കുക"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"ബാറ്ററി ലാഭിക്കൽ ഓഫാക്കുക"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"നിങ്ങളുടെ സ്ക്രീനിൽ പ്രദർശിപ്പിച്ചിരിക്കുന്ന എല്ലാ കാര്യങ്ങളും <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ക്യാപ്ചർ ചെയ്യുന്നത് ആരംഭിക്കും."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"വീണ്ടും കാണിക്കരുത്"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"എല്ലാം മായ്ക്കുക"</string>
@@ -588,8 +580,8 @@
<item quantity="one">%d മിനിറ്റ്</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"ബാറ്ററി ഉപയോഗം"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"ചാർജുചെയ്യുന്ന സമയത്ത് ബാറ്ററി ലാഭിക്കൽ നടക്കില്ല"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"ബാറ്ററി ലാഭിക്കൽ"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ചാർജുചെയ്യുന്ന സമയത്ത് ബാറ്ററി ലാഭിക്കൽ നടക്കില്ല"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"ബാറ്ററി ലാഭിക്കൽ"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"പ്രവർത്തനവും പശ്ചാത്തല ഡാറ്റയും കുറയ്ക്കുന്നു"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"ബട്ടൺ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"ഹോം"</string>
diff --git a/packages/SystemUI/res/values-mn/config.xml b/packages/SystemUI/res/values-mn/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-mn/config.xml
+++ b/packages/SystemUI/res/values-mn/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index c9d1d31..7ecf683 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -32,14 +32,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Мэдэгдэл"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Батерей дуусаж байна"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> үлдсэн"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> үлдсэн. Батерей хэмнэгч ассан."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> үлдсэн. Тэжээл хэмнэгч асаалттай байна."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB цэнэглэлт дэмжигдэхгүй байна.\nЗөвхөн нийлүүлэгдсэн цэнэглэгчийг ашиглана уу."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB-р цэнэглэх дэмжигддэггүй."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Зөвхөн зориулалтын ирсэн цэнэглэгч ашиглана уу."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Тохиргоо"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Батерей хэмнэгчийг асаах уу?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Тэжээл хэмнэгчийг асаах уу?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Асаах"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Батерей хэмнэгчийг асаах"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Тэжээл хэмнэгчийг асаах"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Тохиргоо"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Дэлгэцийг автоматаар эргүүлэх"</string>
@@ -49,15 +49,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Блютүүтыг модем болгож байна"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Оруулах аргыг тохируулах"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Бодит гар"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"<xliff:g id="APPLICATION">%1$s</xliff:g> апп-г USB төхөөрөмжид хандахыг зөвшөөрөх үү?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"<xliff:g id="APPLICATION">%1$s</xliff:g> апп-г USB төхөөрөмжид хандахыг зөвшөөрөх үү?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Энэ USB төхөөрөмж холбогдох үед <xliff:g id="ACTIVITY">%1$s</xliff:g>-г нээх үү?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Энэ USB төхөөрөмж холбогдох үед <xliff:g id="ACTIVITY">%1$s</xliff:g>-г нээх үү?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g>-г <xliff:g id="USB_DEVICE">%2$s</xliff:g>-д хандахыг зөвшөөрөх үү?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g>-г <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>-д хандахыг зөвшөөрөх үү?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>-г зохицуулахын тулд <xliff:g id="APPLICATION">%1$s</xliff:g>-г нээх үү?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>-г зохицуулахын тулд <xliff:g id="APPLICATION">%1$s</xliff:g>-г нээх үү?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Энэ USB хэрэгсэл дээр суулгасан апп ажиллаагүй байна. Энэ хэрэгслийн талаар <xliff:g id="URL">%1$s</xliff:g>-с дэлгэрэнгүй үзнэ үү."</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB төхөөрөмж"</string>
<string name="label_view" msgid="6304565553218192990">"Үзэх"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Энэ USB төхөөрөмжийг үндсэн болгон ашиглах"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Энэ USB төхөөрөмжийг үндсэн болгон ашиглах"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>-г холбогдсон үед <xliff:g id="APPLICATION">%1$s</xliff:g>-г тогтмол нээх"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>-г холбогдсон үед <xliff:g id="APPLICATION">%1$s</xliff:g>-г тогтмол нээх"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB дебаг хийхийг зөвшөөрөх үү?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Компьютерийн RSA түлхүүрийн хурууны хээ :\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Энэ компьютерээс орохыг байнга зөвшөөрөх"</string>
@@ -241,8 +241,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Дата-г түр зогсоосон байна"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Таны тогтоосон датаны хязгаарт хүрсэн тул мобайл дата ашиглалт зогссон байна.\n\nҮргэлжлүүлсэн тохиолдолд дата ашиглалтын төлбөр гарна."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Үргэлжлүүлэх"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет холболт байхгүй"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi холбогдсон"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS хайж байна"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS байршил"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Байршлын хүсэлтүүд идэвхтэй"</string>
@@ -399,9 +397,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Хэрэглэгчийг устгах уу?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Энэ хэрэглэгчийн бүх апп болон мэдээлэл устах болно."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Арилгах"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Батерей хэмнэгч асаалттай"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Тэжээл хэмнэгч асаалттай байна"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Ажиллагаа болон далд датаг бууруулна"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Батерей хэмнэгчийг унтраах"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Тэжээл хэмнэгчийг унтраах"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> таны дэлгэц дээр гаргасан бүх зүйлийн зургийг авч эхэлнэ."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Дахиж үл харуулах"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Бүгдийг арилгах"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d минут</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Тэжээл ашиглалт"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Цэнэглэх үед тэжээл хэмнэгч ажиллахгүй"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Тэжээл хэмнэгч"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Цэнэглэх үед тэжээл хэмнэгч ажиллахгүй"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Тэжээл хэмнэгч"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Гүйцэтгэл болон дэвсгэрийн датаг багасгадаг"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> товчлуур"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Нүүр хуудас"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index b882c5e..a0c9b2c 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -34,14 +34,17 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"सूचना"</string>
<string name="battery_low_title" msgid="6456385927409742437">"बॅटरी कमी आहे"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> शिल्लक"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> शिल्लक. बॅटरी बचतकर्ता चालू आहे."</string>
+ <!-- no translation found for battery_low_percent_format_saver_started (7879389868952879166) -->
+ <skip />
<string name="invalid_charger" msgid="4549105996740522523">"USB चार्जिंग समर्थित नाही.\nफक्त पुरवठा केलेले चार्जर वापरा."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB चार्जिंग समर्थित नाही."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"केवळ पुरविलेले चार्जर वापरा."</string>
<string name="battery_low_why" msgid="4553600287639198111">"सेटिंग्ज"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"बॅटरी बचतकर्ता चालू करायचे?"</string>
+ <!-- no translation found for battery_saver_confirmation_title (2052100465684817154) -->
+ <skip />
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"चालू करा"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"बॅटरी बचतकर्ता चालू करा"</string>
+ <!-- no translation found for battery_saver_start_action (8187820911065797519) -->
+ <skip />
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"सेटिंग्ज"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"वाय-फाय"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"स्वयं-फिरणारी स्क्रीन"</string>
@@ -243,8 +246,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटास विराम दिला आहे"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"आपण सेट केलेली डेटा मर्यादा संपली. आता आपले मोबाइल डेटा वापरणे बंद आहे.\n\nआपण ते पुन्हा सुरू केल्यास, डेटा वापरासाठी शुल्क लागू होईल."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"पुन्हा सुरु करा"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इंटरनेट कनेक्शन नाही"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाय-फाय कनेक्ट केले"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS शोधत आहे"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS द्वारे स्थान सेट केले"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"स्थान विनंत्या सक्रिय"</string>
@@ -401,9 +402,11 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"वापरकर्त्यास काढायचे?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"या वापरकर्त्याचे सर्व अॅप्स आणि डेटा काढून टाकला जाईल."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"काढा"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"बॅटरी बचतकर्ता चालू आहे"</string>
+ <!-- no translation found for battery_saver_notification_title (8614079794522291840) -->
+ <skip />
<string name="battery_saver_notification_text" msgid="820318788126672692">"कामगिरी आणि पार्श्वभूमीवरील डेटा कमी करते"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"बॅटरी बचतकर्ता बंद करा"</string>
+ <!-- no translation found for battery_saver_notification_action_text (132118784269455533) -->
+ <skip />
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> आपल्या स्क्रीनवर प्रदर्शित होणारी प्रत्येक गोष्ट कॅप्चर करणे प्रारंभ करेल."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"पुन्हा दर्शवू नका"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"सर्व साफ करा"</string>
@@ -582,8 +585,8 @@
<item quantity="other"> %d मिनिटे</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"बॅटरी वापर"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"चार्ज करताना बॅटरी सेव्हर उपलब्ध नाही"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"बॅटरी सेव्हर"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"चार्ज करताना बॅटरी बचतकर्ता उपलब्ध नाही"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"बॅटरी बचतकर्ता"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"कामगिरी आणि पार्श्वभूमीवरील डेटा कमी करते"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"बटण <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-ms/config.xml b/packages/SystemUI/res/values-ms/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-ms/config.xml
+++ b/packages/SystemUI/res/values-ms/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index fad7563..78708f7 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Pemberitahuan"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Bateri lemah"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> yang tinggal"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> yang tinggal. Penjimat bateri dihidupkan."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Tinggal <xliff:g id="PERCENTAGE">%s</xliff:g>. Penjimat Bateri dihidupkan."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Pengecasan USB tidak disokong.\nGunakan hanya pengecas yang dibekalkan."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Pengecasan USB tidak disokong."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Gunakan pengecas yang dibekalkan sahaja."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Tetapan"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Hidupkan penjimat bateri?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Hidupkan Penjimat Bateri?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Hidupkan"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Hidupkan penjimat bateri"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Hidupkan Penjimat Bateri"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Tetapan"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Autoputar skrin"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth ditambatkan"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Sediakan kaedah input"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Papan kekunci fizikal"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Benarkan aplikasi <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses peranti USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Benarkan aplikasi <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses aksesori USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Buka <xliff:g id="ACTIVITY">%1$s</xliff:g> apabila peranti USB ini disambungkan?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Buka <xliff:g id="ACTIVITY">%1$s</xliff:g> apabila aksesori USB ini disambungkan?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Benarkan <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Benarkan <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Buka <xliff:g id="APPLICATION">%1$s</xliff:g> untuk mengendalikan <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Buka <xliff:g id="APPLICATION">%1$s</xliff:g> untuk mengendalikan <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Tiada apl yg dipsg bfungsi dgn aksesori USB ini. Ketahui lg ttg aksesori ini di <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Aksesori USB"</string>
<string name="label_view" msgid="6304565553218192990">"Lihat"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Gunakan secara lalai untuk peranti USB ini"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Gunakan secara lalai untuk aksesori USB ini"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Sentiasa buka <xliff:g id="APPLICATION">%1$s</xliff:g> apabila <xliff:g id="USB_DEVICE">%2$s</xliff:g> disambungkan"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Sentiasa buka <xliff:g id="APPLICATION">%1$s</xliff:g> apabila <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> disambungkan"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Benarkan penyahpepijatan USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Cap jari kekunci RSA komputer ialah:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Sentiasa benarkan komputer ini"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data dijeda"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Had data yang anda tetapkan telah dicapai. Anda tidak lagi menggunakan data mudah alih.\n\nJika anda menyambung semula, caj mungkin digunakan untuk penggunaan data."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Sambung semula"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tiada smbg Internet"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi disambungkan"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Mencari GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasi ditetapkan oleh GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Permintaan lokasi aktif"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Alih keluar pengguna?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Semua apl dan data pengguna ini akan dipadamkan."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Alih keluar"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Penjimat bateri dihidupkan"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Penjimat Bateri dihidupkan"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Mengurangkan prestasi dan data latar belakang"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Matikan penjimat bateri"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Matikan Penjimat Bateri"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> akan mula mengabadikan semua yang dipaparkan pada skrin anda.."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Jangan tunjukkan lagi"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Kosongkan semua"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d minit</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Penggunaan bateri"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Penjimat bateri tidak tersedia semasa mengecas"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Penjimat bateri"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Penjimat Bateri tidak tersedia semasa mengecas"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Penjimat Bateri"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Mengurangkan prestasi dan data latar belakang"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Butang <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Skrin Utama"</string>
diff --git a/packages/SystemUI/res/values-my/config.xml b/packages/SystemUI/res/values-my/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-my/config.xml
+++ b/packages/SystemUI/res/values-my/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index faa1f1a..a3ec0db 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"အကြောင်းကြားချက်များ။"</string>
<string name="battery_low_title" msgid="6456385927409742437">"ဘက်ထရီ အားနည်းနေ"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> ကျန်ရှိနေ"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> ကျန်ရှိနေ။ ဘက်ထရီ ချွေတာမှု ဖွင့်ထား။"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> ကျန်ပါတယ်။ ဘက်ထရီ အားထိန်းကို ဖွင့်ထားသည်။"</string>
<string name="invalid_charger" msgid="4549105996740522523">"လက်ရှိUSBအားသွင်းခြင်း အသုံးမပြုနိုင်ပါ \n ပေးထားသောအားသွင်းကိရိယာကိုသာ အသုံးပြုပါ"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB အားသွင်းမှု မပံ့ပိုးပါ။"</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"ပေးခဲ့သည့် အားသွင်းစက်ကိုသာ အသုံးပြုပါ"</string>
<string name="battery_low_why" msgid="4553600287639198111">"ဆက်တင်များ"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"ဘက်ထရီ ချွေတာမှုကို ဖွင့်ရမလား?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"ဘက်ထရီ အားထိန်းကို ဖွင့်ခြင်း"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"ဖွင့်ရန်"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"ဘက်ထရီ ချွေတာမှုကို ဖွင့်ရန်"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"ဘက်ထရီ အားထိန်းကို ဖွင့်ရန်"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"အပြင်အဆင်များ"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"မျက်နှာပြင်အလိုအလျောက်လှည့်ရန်"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"ဘလူးတုသ်မှတဆင့်ပြန်လည်ချိတ်ဆက်ခြင်း"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ထည့်သွင်းနည်းများ သတ်မှတ်ခြင်း"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"ခလုတ်ပါဝင်သော ကီးဘုတ်"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"<xliff:g id="APPLICATION">%1$s</xliff:g>အပ်ပလီကေးရှင်းအား USBပစ္စည်းကို ချိတ်ဆက်ရန်ခွင့်ပြုမည်လား"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"<xliff:g id="APPLICATION">%1$s</xliff:g> အပ်ပလီကေးရှင်းကို USB တွဲဖက်ပစ္စည်းများအား ဝင်ရောက်ကြည့်ရှုရန်ခွင့်ပြုသည်"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"<xliff:g id="ACTIVITY">%1$s</xliff:g> အားUSBပစ္စည်း ချိတ်ဆက်နေစဥ် ဖွင့်မည်လား"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"<xliff:g id="ACTIVITY">%1$s</xliff:g> အား USBတွဲဖက်ပစ္စည်း ချိတ်ဆက်ထားစဥ် ဖွင့်မည်"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> အား ဝင်သုံးရန် <xliff:g id="APPLICATION">%1$s</xliff:g> ကို ခွင့်ပြုပါသလား။"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> အား ဝင်သုံးရန် <xliff:g id="APPLICATION">%1$s</xliff:g> ကို ခွင့်ပြုပါသလား။"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ဆောင်ရွက်ရန် <xliff:g id="APPLICATION">%1$s</xliff:g> ကို ဖွင့်လိုပါသလား။"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ဆောင်ရွက်ရန် <xliff:g id="APPLICATION">%1$s</xliff:g> ကို ဖွင့်လိုပါသလား။"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ဒီUSBပစ္စည်းနှင့်ဘယ်အပ်ပလီကေးရှင်းမှ အလုပ်မလုပ်ပါ။ ပိုမိုသိရန် <xliff:g id="URL">%1$s</xliff:g>တွင် လေ့လာပါ"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USBတွဲဖက်ပစ္စည်းများ"</string>
<string name="label_view" msgid="6304565553218192990">"မြင်ကွင်း"</string>
- <string name="always_use_device" msgid="1450287437017315906">"ဤUSBပစ္စည်းများအတွက် မူရင်းအတိုင်း အသုံးပြုပါ။"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"ဤUSB အပိုပစ္စည်းများအတွက် မူရင်းအတိုင်း အသုံးပြုပါ။"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ချိတ်ဆက်သည့်အခါ <xliff:g id="APPLICATION">%1$s</xliff:g> ကို အမြဲဖွင့်ပါ"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ချိတ်ဆက်သည့်အခါ <xliff:g id="APPLICATION">%1$s</xliff:g> ကို အမြဲဖွင့်ပါ"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB အမှားရှာဖွေပြင်ဆင်ခြင်း ခွင့်ပြုပါမည်လား?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"ဒီကွန်ပျူတာရဲ့ RSA key fingerprint ကတော့:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g> ဖြစ်ပါသည်"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"ဒီကွန်ပျူတာမှ အမြဲခွင့်ပြုရန်"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ဒေတာ ခေတ္တရပ်တန့်သည်"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"သင်သတ်မှတ်ထားသော ဒေတာကန့်သတ်ချက်သို့ ရောက်နေပါပြီ။ သင်သည် မိုဘိုင်းဒေတာကို အသုံးပြုနေခြင်း မရှိတော့ပါ။\n\nဆက်သုံးမည်ဆိုလျှင် ဒေတာသုံးစွဲခ ကျသင့်နိုင်ပါသည်။"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ပြန်ဆက်လုပ်ရန်"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"အင်တာနက်မရှိ"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ကြိုးမဲ့ဆက်သွယ်မှု"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPSအားရှာဖွေသည်"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPSမှတည်နေရာကိုအတည်ပြုသည်"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"တည်နေရာပြ တောင်းဆိုချက်များ အသက်ဝင်ရန်"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"သုံးစွဲသူကိုဖယ်ရှားမည်လား?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"ဤအသုံးပြုသူ၏ ဒေတာနှင့် အပ်ဖ်များအားလုံး ဖျက်လိုက်ပါမည်"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"ဖယ်ရှားရန်"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"ဘက်ထရီ ချွေတာသူ ဖွင့်ထား"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"ဘက်ထရီ အားထိန်းကို ဖွင့်ထားခြင်း"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"လုပ်ကိုင်မှုကို လျှော့ချလျက် နောက်ခံ ဒေတာကို ကန့်သတ်သည်"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ဘက်ထရီ ချွေတာမှုကို ပိတ်ထားရန်"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"ဘက်ထရီ အားထိန်းကို ပိတ်ရန်"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> က သင်၏ မျက်နှာပြင် ပေါ်မှာ ပြသထားသည့် အရာတိုင်းကို စတင် ဖမ်းယူမည်။"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"နောက်ထပ် မပြပါနှင့်"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"အားလုံး ဖယ်ရှားရန်"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d မိနစ်</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"ဘက်ထရီ အသုံးပြုမှု"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"အားသွင်းနေစဉ် ဘက်ထရီချွေတာမှုစနစ်ကို သုံး၍ မရပါ"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"ဘက်ထရီ ချွေတာမှုစနစ်"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"အားသွင်းနေချိန်မှာ Battery Saver ကို သုံးမရပါ"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Battery Saver"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"လုပ်ဆောင်မှု နှင့် နောက်ခံ ဒေတာကို လျော့နည်းစေပါသည်"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"ခလုတ် <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"ပင်မ"</string>
diff --git a/packages/SystemUI/res/values-nb/config.xml b/packages/SystemUI/res/values-nb/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-nb/config.xml
+++ b/packages/SystemUI/res/values-nb/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 77af297..bebfad5 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -24,7 +24,7 @@
<string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Fjern fra listen"</string>
<string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Info om appen"</string>
<string name="status_bar_no_recent_apps" msgid="7374907845131203189">"De sist brukte skjermene dine vises her"</string>
- <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Avvis nylige apper"</string>
+ <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Avvis nylig brukte apper"</string>
<plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
<item quantity="other">%d skjermer i oversikten</item>
<item quantity="one">1 skjerm i oversikten</item>
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Varsler"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Batterikapasiteten er lav"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> gjenstår"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> gjenstår. Batterisparing er på."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> gjenstår. Batterisparing er på."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-lading støttes ikke.\nBruk kun den medfølgende laderen."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Lading via USB støttes ikke."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Bruk bare den tilhørende laderen."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Innstillinger"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Vil du slå på batterisparing?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Vil du slå på batterisparing?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Slå på"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Slå på batterisparing"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Slå på batterisparing"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Innstillinger"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Trådløse nettverk"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rotér skjermen automatisk"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tilknyttet"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfigurer inndatametoder"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fysisk tastatur"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Vil du gi appen <xliff:g id="APPLICATION">%1$s</xliff:g> tilgang til USB-enheten?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vil du gi appen <xliff:g id="APPLICATION">%1$s</xliff:g> tilgang til USB-tilbehøret?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vil du åpne <xliff:g id="ACTIVITY">%1$s</xliff:g> når denne USB-enheten er tilkoblet?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Vil du åpne <xliff:g id="ACTIVITY">%1$s</xliff:g> når dette USB-tilbehøret er tilkoblet?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Vil du gi <xliff:g id="APPLICATION">%1$s</xliff:g> tilgang til <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Vil du gi <xliff:g id="APPLICATION">%1$s</xliff:g> tilgang til <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Vil du åpne <xliff:g id="APPLICATION">%1$s</xliff:g> for å behandle <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Vil du åpne <xliff:g id="APPLICATION">%1$s</xliff:g> for å behandle <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Ingen installerte apper støtter dette USB-tilbehøret. Les mer om tilbehøret på <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB-enhet"</string>
<string name="label_view" msgid="6304565553218192990">"Vis"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Bruk som standard for denne USB-enheten"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Bruk som standard for dette USB-tilbehøret"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Åpne alltid <xliff:g id="APPLICATION">%1$s</xliff:g> når <xliff:g id="USB_DEVICE">%2$s</xliff:g> er koblet til"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Åpne alltid <xliff:g id="APPLICATION">%1$s</xliff:g> når <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> er koblet til"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Vil du tillate USB-feilsøking?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Datamaskinens nøkkelfingeravtrykk for RSA er:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Tillat alltid fra denne datamaskinen"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data er satt på pause"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Datagrensen du har angitt, er nådd. Du bruker ikke lenger mobildata.\n\nHvis du fortsetter, kan avgifter for databruk påløpe."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Gjenoppta"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen Internett-forbindelse"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tilkoblet"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Søker etter GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Posisjon angitt av GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Aktive stedsforespørsler"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Vil du fjerne brukeren?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Alle apper og data som tilhører denne brukeren, blir slettet."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Fjern"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Batterisparing er på"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Batterisparing er på"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduserer ytelsen og begrenser bakgrunnsdataene"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Slå av batterisparing"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Slå av batterisparing"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tar opp alt som vies på skjermen din."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ikke vis igjen"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Fjern alt"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d minutt</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Batteribruk"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Batterisparing er ikke tilgjengelig under lading"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Batterisparing"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterisparing er ikke tilgjengelig under lading"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Batterisparing"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduserer ytelsen og begrenser bakgrunnsdataene"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g>-knappen"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Startskjerm"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index e994174..bfe8f07 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"सूचनाहरू"</string>
<string name="battery_low_title" msgid="6456385927409742437">"ब्याट्री कम छ"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> बाँकी"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> बाँकी। ब्याट्री बचत खुलै छ।"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> बाँकी। ब्याट्री सेभर सक्रिय छ।"</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB चार्ज गर्न समर्थित छैन।\n आपूर्ति गरिएको चार्जर मात्र प्रयोग गर्नुहोस्।"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB चार्ज समर्थित छैन।"</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"आपूर्ति गरिएको चार्जर मात्र प्रयोग गर्नुहोस्।"</string>
<string name="battery_low_why" msgid="4553600287639198111">"सेटिङ्हरू"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"ब्याट्री बचत खोल्नुहुन्छ?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"ब्याट्री सेभर सक्रिय गर्ने हो?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"खोल्नुहोस्"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"ब्याट्री बचत खोल्नुहोस्"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"ब्याट्री सेभर सक्रिय गर्नुहोस्"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"सेटिङहरू"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"स्वत:घुम्ने स्क्रिन"</string>
@@ -51,21 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"ब्लुटुथ टेथर भयो"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"इनपुट विधिहरू सेटअप गर्नुहोस्"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"वास्तविक किबोर्ड"</string>
- <!-- no translation found for usb_device_permission_prompt (1825685909587559679) -->
- <skip />
- <!-- no translation found for usb_accessory_permission_prompt (2465531696941369047) -->
- <skip />
- <!-- no translation found for usb_device_confirm_prompt (7440562274256843905) -->
- <skip />
- <!-- no translation found for usb_accessory_confirm_prompt (4333670517539993561) -->
- <skip />
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> लाई <xliff:g id="USB_DEVICE">%2$s</xliff:g> माथि पहुँच राख्ने अनुमति दिने हो?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> लाई <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> माथि पहुँच राख्ने अनुमति दिने हो?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> को व्यवस्थापन गर्न <xliff:g id="APPLICATION">%1$s</xliff:g> खोल्ने हो?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> को व्यवस्थापन गर्न <xliff:g id="APPLICATION">%1$s</xliff:g> खोल्ने हो?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"यस USB उपकरणसँग स्थापित अनुप्रयोग काम गर्दैन। यस उपकरणको बारेमा <xliff:g id="URL">%1$s</xliff:g> मा धेरै जान्नुहोस्"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB सहयोगी"</string>
<string name="label_view" msgid="6304565553218192990">"दृश्य"</string>
- <!-- no translation found for always_use_device (4015357883336738417) -->
- <skip />
- <!-- no translation found for always_use_accessory (3257892669444535154) -->
- <skip />
+ <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> जडान भएको बेला सधैँ <xliff:g id="APPLICATION">%1$s</xliff:g> खोल्नुहोस्"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> जडान भएको बेला सधैँ <xliff:g id="APPLICATION">%1$s</xliff:g> खोल्नुहोस्"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB डिबग गर्नको लागि अनुमति दिने हो?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"कम्प्युटरको RSA कुञ्जी औंलाछाप:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"यो कम्प्युटरबाट सधैँ अनुमति दिनुहोस्"</string>
@@ -249,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटा रोकिएको छ"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"तपाईंले सेट गर्नुभएको डेटाको अधिकतम सीमामा पुगिएको छ। तपाईंले अब उप्रान्त मोबाइल डेटाको प्रयोग गर्नुहुने छैन। \n\nतपाईंले प्रयोग जारी राख्नुभयो भने डेटा प्रयोगका शुल्कहरू लाग्न सक्छन्।"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"पुनः सुरु गर्नुहोस्"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इन्टरनेट जडान छैन"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi जडित"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPSको लागि खोजी गर्दै"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS द्वारा स्थान सेट गरिएको"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"स्थान अनुरोधहरू सक्रिय"</string>
@@ -407,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"प्रयोगकर्ता हटाउन चाहनुहुन्छ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"यस प्रयोगकर्ताको सबै अनुप्रयोगहरू तथा डेटा हटाइनेछ।"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"हटाउनुहोस्"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"ब्याट्री सेभर चालु छ"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"ब्याट्री सेभर सक्रिय छ"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"प्रदर्शन र पृष्ठभूमि डेटा घटाउँनुहोस्"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ब्याट्री बचत बन्द गर्नुहोस्"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"ब्याट्री सेभर निष्क्रिय पार्नुहोस्"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ले आफ्नो स्क्रीनमा प्रदर्शित हुने सबै खिच्न शुरू गर्नेछ।"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"फेरि नदेखाउनुहोस्"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"सबै हटाउनुहोस्"</string>
@@ -588,8 +580,8 @@
<item quantity="one">%d मिनेट</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"ब्याट्री उपयोग"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"चार्ज गर्ने समयमा ब्याट्री सेवर उपलब्ध छैन"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"ब्याट्री सेवर"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"चार्ज गर्ने समयमा ब्याट्री सेभर उपलब्ध छैन"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"ब्याट्री सेभर"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"कार्यसम्पादन र पृष्ठभूमि डेटा घटाउँछ"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> बटन"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 640b5d0..98ad14f 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meldingen"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Batterij is bijna leeg"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> resterend"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> resterend. Batterijbesparing is ingeschakeld."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> resterend. Batterijbesparing is ingeschakeld."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Opladen via USB niet ondersteund.\nGebruik alleen de bijgeleverde oplader."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Opladen via USB wordt niet ondersteund."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Gebruik alleen de bijgeleverde oplader."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Instellingen"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Batterijbesparing inschakelen?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Batterijbesparing inschakelen?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Inschakelen"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Batterijbesparing inschakelen"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Batterijbesparing inschakelen"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Instellingen"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wifi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Scherm automatisch draaien"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Gegevens zijn onderbroken"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"De datalimiet die je hebt ingesteld, is bereikt. Je gebruikt geen mobiele data meer.\n\nAls je hervat, kunnen er kosten voor datagebruik in rekening worden gebracht."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervatten"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Verbonden via wifi"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Zoeken naar gps"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Locatie bepaald met gps"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Locatieverzoeken actief"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Gebruiker verwijderen?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Alle apps en gegevens van deze gebruiker worden verwijderd."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Verwijderen"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Batterijbesparing is ingeschakeld"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Batterijbesparing aan"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Vermindert de prestaties en achtergrondgegevens"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Batterijbesparing uitschakelen"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Batterijbesparing uitschakelen"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> gaat alles vastleggen dat wordt weergegeven op je scherm."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Niet opnieuw weergeven"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Alles wissen"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d minuut</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Accugebruik"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Batterijbesparing niet beschikbaar tijdens opladen"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Batterijbesparing"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterijbesparing niet beschikbaar tijdens opladen"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Batterijbesparing"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Vermindert de prestaties en achtergrondgegevens"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Knop <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 48be371..8706298 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -34,14 +34,17 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"ਸੂਚਨਾਵਾਂ"</string>
<string name="battery_low_title" msgid="6456385927409742437">"ਬੈਟਰੀ ਘੱਟ ਹੈ"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> ਬਾਕੀ"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> ਬਾਕੀ। ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਹੈ।"</string>
+ <!-- no translation found for battery_low_percent_format_saver_started (7879389868952879166) -->
+ <skip />
<string name="invalid_charger" msgid="4549105996740522523">"USB ਚਾਰਜਿੰਗ ਸਮਰਥਿਤ ਨਹੀਂ ਹੈ।\nਕੇਵਲ ਸਪਲਾਈ ਕੀਤਾ ਚਾਰਜਰ ਵਰਤੋ।"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB ਚਾਰਜਿੰਗ ਸਮਰਥਿਤ ਨਹੀਂ ਹੈ।"</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"ਕੇਵਲ ਸਪਲਾਈ ਕੀਤਾ ਚਾਰਜਰ ਵਰਤੋ।"</string>
<string name="battery_low_why" msgid="4553600287639198111">"ਸੈਟਿੰਗਾਂ"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"ਕੀ ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
+ <!-- no translation found for battery_saver_confirmation_title (2052100465684817154) -->
+ <skip />
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"ਚਾਲੂ ਕਰੋ"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਕਰੋ"</string>
+ <!-- no translation found for battery_saver_start_action (8187820911065797519) -->
+ <skip />
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ਸੈਟਿੰਗਾਂ"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"ਵਾਈ-ਫਾਈ"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"ਸਕ੍ਰੀਨ ਆਪਣੇ-ਆਪ ਘੁੰਮਾਓ"</string>
@@ -51,21 +54,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth ਟੀਥਰ ਕੀਤੀ"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ਇਨਪੁਟ ਵਿਧੀਆਂ ਸੈਟ ਅਪ ਕਰੋ"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"ਫਿਜੀਕਲ ਕੀ-ਬੋਰਡ"</string>
- <!-- no translation found for usb_device_permission_prompt (1825685909587559679) -->
- <skip />
- <!-- no translation found for usb_accessory_permission_prompt (2465531696941369047) -->
- <skip />
- <!-- no translation found for usb_device_confirm_prompt (7440562274256843905) -->
- <skip />
- <!-- no translation found for usb_accessory_confirm_prompt (4333670517539993561) -->
- <skip />
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"ਕੀ <xliff:g id="USB_DEVICE">%2$s</xliff:g> ਤੱਕ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨੂੰ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"ਕੀ <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ਤੱਕ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨੂੰ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"ਕੀ <xliff:g id="USB_DEVICE">%2$s</xliff:g> ਨੂੰ ਵਰਤਣ ਲਈ <xliff:g id="APPLICATION">%1$s</xliff:g> ਖੋਲ੍ਹਣੀ ਹੈ?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"ਕੀ <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ਨੂੰ ਵਰਤਣ ਲਈ <xliff:g id="APPLICATION">%1$s</xliff:g> ਖੋਲ੍ਹਣੀ ਹੈ?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ਕੋਈ ਇੰਸਟੌਲ ਕੀਤੇ ਐਪਸ ਇਸ USB ਐਕਸੈਸਰੀ ਨਾਲ ਕੰਮ ਨਹੀਂ ਕਰਦੇ। <xliff:g id="URL">%1$s</xliff:g> ਤੇ ਇਸ ਐਕਸੈਸਰੀ ਬਾਰੇ ਹੋਰ ਜਾਣੋ"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB ਐਕਸੈਸਰੀ"</string>
<string name="label_view" msgid="6304565553218192990">"ਦੇਖੋ"</string>
- <!-- no translation found for always_use_device (4015357883336738417) -->
- <skip />
- <!-- no translation found for always_use_accessory (3257892669444535154) -->
- <skip />
+ <string name="always_use_device" msgid="4015357883336738417">"ਹਮੇਸ਼ਾਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨੂੰ ਉਦੋਂ ਹੀ ਖੋਲ੍ਹੋ ਜਦੋਂ <xliff:g id="USB_DEVICE">%2$s</xliff:g> ਕਨੈਕਟ ਹੋਵੇ"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"ਹਮੇਸ਼ਾਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨੂੰ ਉਦੋਂ ਹੀ ਖੋਲ੍ਹੋ ਜਦੋਂ <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ਕਨੈਕਟ ਹੋਵੇ"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"ਕੀ USB ਡੀਬਗਿੰਗ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"ਕੰਪਿਊਟਰ ਦਾ RSA ਕੁੰਜੀ ਫਿੰਗਰਪ੍ਰਿੰਟ \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"ਹਮੇਸ਼ਾਂ ਇਸ ਕੰਪਿਊਟਰ ਤੋਂ ਆਗਿਆ ਦਿਓ"</string>
@@ -249,8 +246,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">" ਡਾਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"ਤੁਸੀਂ ਤੁਹਾਡੇ ਵੱਲੋਂ ਸੈੱਟ ਕੀਤੀ ਗਈ ਡਾਟਾ ਸੀਮਾ \'ਤੇ ਪਹੁੰਚ ਚੁੱਕੇ ਹੋ। ਤੁਸੀਂ ਹੁਣ ਮੋਬਾਈਲ ਡਾਟੇ ਦੀ ਵਰਤੋਂ ਨਹੀਂ ਕਰ ਰਹੇ ਹੋ।\n\nਜੇਕਰ ਤੁਸੀਂ ਮੁੜ-ਸ਼ੁਰੂ ਕਰਦੇ ਹੋ, ਤਾਂ ਡਾਟਾ ਵਰਤੋਂ ਲਈ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ।"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ਦੁਬਾਰਾ ਸ਼ੁਰੂ ਕਰੋ"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ਕੋਈ ਇੰਟਰਨੈੱਟ ਕਨੈਕਸ਼ਨ ਨਹੀਂ"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ਵਾਈ-ਫਾਈ ਕਨੈਕਟ ਹੈ"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS ਦੀ ਖੋਜ ਕਰ ਰਿਹਾ ਹੈ"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS ਵੱਲੋਂ ਸੈੱਟ ਕੀਤਾ ਗਿਆ ਟਿਕਾਣਾ"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸੇਵਾ ਬੇਨਤੀਆਂ ਸਕਿਰਿਆ"</string>
@@ -407,9 +402,11 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"ਕੀ ਵਰਤੋਂਕਾਰ ਹਟਾਉਣਾ ਹੈ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"ਇਸ ਉਪਭੋਗਤਾ ਦੇ ਸਾਰੇ ਐਪਸ ਅਤੇ ਡਾਟਾ ਮਿਟਾ ਦਿੱਤਾ ਜਾਏਗਾ।"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"ਹਟਾਓ"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਹੈ"</string>
+ <!-- no translation found for battery_saver_notification_title (8614079794522291840) -->
+ <skip />
<string name="battery_saver_notification_text" msgid="820318788126672692">"ਪ੍ਰਦਰਸ਼ਨ ਅਤੇ ਪਿਛੋਕੜ ਡਾਟਾ ਘੱਟ ਕਰਦਾ ਹੈ"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ਬੈਟਰੀ ਸੇਵਰ ਬੰਦ ਕਰੋ"</string>
+ <!-- no translation found for battery_saver_notification_action_text (132118784269455533) -->
+ <skip />
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ਉਹ ਸਭ ਕੁਝ ਕੈਪਚਰ ਕਰਨਾ ਸ਼ੁਰੂ ਕਰ ਦੇਵੇਗਾ, ਜੋ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਤੇ ਡਿਸਪਲੇ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"ਦੁਬਾਰਾ ਨਾ ਦਿਖਾਓ"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string>
@@ -588,8 +585,8 @@
<item quantity="other"> %d ਮਿੰਟ</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"ਬੈਟਰੀ ਵਰਤੋਂ"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"ਬੈਟਰੀ ਸੇਵਰ ਚਾਰਜਿੰਗ ਦੌਰਾਨ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"ਬੈਟਰੀ ਸੇਵਰ"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ਬੈਟਰੀ ਸੇਵਰ ਚਾਰਜਿੰਗ ਦੌਰਾਨ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"ਬੈਟਰੀ ਸੇਵਰ"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"ਕਾਰਗੁਜ਼ਾਰੀ ਅਤੇ ਬੈਕਗ੍ਰਾਊਂਡ ਡਾਟੇ ਨੂੰ ਘਟਾਉਂਦਾ ਹੈ"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"ਬਟਨ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-pl/config.xml b/packages/SystemUI/res/values-pl/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-pl/config.xml
+++ b/packages/SystemUI/res/values-pl/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index fdd4c02..56a8e59 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -36,14 +36,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Powiadomienia"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Niski poziom baterii"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Pozostało <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Pozostało <xliff:g id="PERCENTAGE">%s</xliff:g>. Oszczędzanie baterii jest włączone."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Pozostało <xliff:g id="PERCENTAGE">%s</xliff:g>. Oszczędzanie baterii jest włączone."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Ładowanie przy użyciu złącza USB nie jest obsługiwane.\nNależy używać tylko dołączonej ładowarki."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Ładowanie przez USB nie jest obsługiwane."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Używaj tylko ładowarki dostarczonej z urządzeniem."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Ustawienia"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Włączyć oszczędzanie baterii?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Włączyć Oszczędzanie baterii?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Włącz"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Włącz oszczędzanie baterii"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Włączyć Oszczędzanie baterii?"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ustawienia"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Autoobracanie ekranu"</string>
@@ -53,15 +53,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth – podłączono"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfiguruj metody wprowadzania"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Klawiatura fizyczna"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Zezwolić aplikacji <xliff:g id="APPLICATION">%1$s</xliff:g> na dostęp do urządzenia USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Zezwolić aplikacji <xliff:g id="APPLICATION">%1$s</xliff:g> na dostęp do urządzenia USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Czy otworzyć <xliff:g id="ACTIVITY">%1$s</xliff:g> po podłączeniu tego urządzenia USB?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Czy otworzyć <xliff:g id="ACTIVITY">%1$s</xliff:g> po podłączeniu tego akcesorium USB?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Zezwolić aplikacji <xliff:g id="APPLICATION">%1$s</xliff:g> na dostęp do urządzenia <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Zezwolić aplikacji <xliff:g id="APPLICATION">%1$s</xliff:g> na dostęp do urządzenia <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Otworzyć aplikację <xliff:g id="APPLICATION">%1$s</xliff:g> do obsługi urządzenia <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Otworzyć aplikację <xliff:g id="APPLICATION">%1$s</xliff:g> do obsługi urządzenia <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Zainstalowane aplikacje nie działają z tym akcesorium USB. Więcej informacji: <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Akcesorium USB"</string>
<string name="label_view" msgid="6304565553218192990">"Wyświetl"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Używaj domyślnie dla tego urządzenia USB"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Używaj domyślnie dla tego akcesorium USB"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Zawsze otwieraj: <xliff:g id="APPLICATION">%1$s</xliff:g> po podłączeniu urządzenia <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Zawsze otwieraj: <xliff:g id="APPLICATION">%1$s</xliff:g> po podłączeniu urządzenia <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Zezwalać na debugowanie USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Odcisk cyfrowy klucza RSA komputera to:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Zawsze zezwalaj z tego komputera"</string>
@@ -243,10 +243,8 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Transmisja danych 4G została wstrzymana"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="6801382439018099779">"Mobilna transmisja danych jest wstrzymana"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Transmisja danych została wstrzymana"</string>
- <string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Osiągnięto ustawiony limit danych. Nie korzystasz już z komórkowej transmisji danych.\n\nJeśli włączysz ją ponownie, może zostać naliczona opłata za użycie danych."</string>
+ <string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Osiągnięto ustawiony limit danych. Nie korzystasz już z mobilnej transmisji danych.\n\nJeśli włączysz ją ponownie, może zostać naliczona opłata za użycie danych."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Wznów"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Brak internetu"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: połączono"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Wyszukiwanie sygnału GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokalizacja z GPSa"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Prośby o lokalizację są aktywne"</string>
@@ -405,9 +403,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Usunąć użytkownika?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Wszystkie aplikacje i dane tego użytkownika zostaną usunięte."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Usuń"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Oszczędzanie baterii jest włączone"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Oszczędzanie baterii jest włączone"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Zmniejsza wydajność i ogranicza dane w tle"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Wyłącz oszczędzanie baterii"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Wyłącz Oszczędzanie baterii"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> będzie zapisywać wszystko, co wyświetli się na ekranie."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Nie pokazuj ponownie"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Ukryj wszystkie"</string>
@@ -594,8 +592,8 @@
<item quantity="one">]%d minuta</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Wykorzystanie baterii"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Oszczędzanie baterii nie jest dostępne podczas ładowania"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Oszczędzanie baterii"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Oszczędzanie baterii nie jest dostępne podczas ładowania"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Oszczędzanie baterii"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Zmniejsza wydajność i ogranicza dane w tle"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Przycisk <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index ce457be..a7c3af1 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Bateria fraca"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> restantes"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> restantes. A Economia de bateria está ativada."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante(s). A Economia de bateria está ativada."</string>
<string name="invalid_charger" msgid="4549105996740522523">"O carregamento via USB não é suportado.\nUse apenas o carregador fornecido."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"O carregamento via USB não é suportado."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Use apenas o carregador fornecido."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Configurações"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Ativar a economia de bateria?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Ativar Economia de bateria?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Ativar"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Ativar a economia de bateria"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Ativar a Economia de bateria"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configurações"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Girar tela automaticamente"</string>
@@ -245,8 +245,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os dados foram pausados"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"O limite de dados que você definiu foi atingido. Você não está mais usando dados móveis.\n\nSe retomar o uso de dados, o serviço poderá ser cobrado."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem conexão à Internet"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Local definido por GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Solicitações de localização ativas"</string>
@@ -403,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Remover usuário?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Todos os apps e dados deste usuário serão excluídos."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Remover"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"A Economia de bateria está ativada"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Economia de bateria ativada"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduz o desempenho e os dados em segundo plano"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desativar a economia de bateria"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Desativar a Economia de bateria"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> começará a capturar tudo o que for exibido na tela."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Não mostrar novamente"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Limpar tudo"</string>
@@ -584,8 +582,8 @@
<item quantity="other">%d minutos</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Uso da bateria"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"O recurso \"Economia de bateria\" não fica disponível durante o carregamento"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Economia de bateria"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"A Economia de bateria não fica disponível durante o carregamento"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Economia de bateria"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduz o desempenho e os dados em segundo plano"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/config.xml b/packages/SystemUI/res/values-pt-rPT/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-pt-rPT/config.xml
+++ b/packages/SystemUI/res/values-pt-rPT/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 2bbc470..b5b3475 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -26,22 +26,22 @@
<string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Os ecrãs recentes aparecem aqui"</string>
<string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Ignorar aplicações recentes"</string>
<plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
- <item quantity="one">1 ecrã na Vista geral</item>
<item quantity="other">%d ecrãs na Vista geral</item>
+ <item quantity="one">1 ecrã na Vista geral</item>
</plurals>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Sem notificações"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Em curso"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Bateria fraca"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante. A poupança da bateria está ativada."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante. A Poupança de bateria está ativada."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Carregamento USB não suportado. \nUtilize apenas o carregador fornecido."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"O carregamento por USB não é suportado."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Utilize apenas o carregador fornecido."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Definições"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Ativar a poupança de bateria?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Pretende ativar a Poupança de bateria?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Ativar"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Ativar a poupança de bateria"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Ativar a Poupança de bateria"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Definições"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rodar ecrã automaticamente"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth ligado"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configurar métodos introdução"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Teclado físico"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Permitir que a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> aceda ao dispositivo USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Permitir que a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> aceda ao acessório USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Abrir <xliff:g id="ACTIVITY">%1$s</xliff:g> quando este dispositivo USB estiver ligado?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Abrir <xliff:g id="ACTIVITY">%1$s</xliff:g> quando este acessório USB estiver ligado?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Pretende permitir que a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> aceda ao dispositivo <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Pretende permitir que a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> aceda ao acessório <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Pretende abrir a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> para controlar o acessório <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Pretende abrir a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> para controlar o acessório <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Nenhuma das aplicações instaladas funciona com o acessório USB. Saiba mais acerca do acessório em <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Acessório USB"</string>
<string name="label_view" msgid="6304565553218192990">"Ver"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Utilizar por predefinição para este aparelho USB"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Utilizar por predefinição para este acessório USB"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Abrir sempre <xliff:g id="APPLICATION">%1$s</xliff:g> quando o dispositivo <xliff:g id="USB_DEVICE">%2$s</xliff:g> estiver ligado"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Abrir sempre <xliff:g id="APPLICATION">%1$s</xliff:g> quando o acessório <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> estiver ligado"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Permitir depuração USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"A impressão digital da chave RSA do computador é:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Permitir sempre a partir deste computador"</string>
@@ -243,16 +243,14 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dados em pausa"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"O limite de dados definido foi atingido. Já não está a utilizar dados móveis.\n\nSe retomar, podem aplicar-se custos relativos à utilização de dados."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem ligação internet"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ligado"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"A procurar GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Localização definida por GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Pedidos de localização ativos"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Limpar todas as notificações."</string>
<string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<plurals name="notification_group_overflow_description" formatted="false" msgid="4579313201268495404">
- <item quantity="one">Mais <xliff:g id="NUMBER_0">%s</xliff:g> notificação no grupo.</item>
<item quantity="other">Mais <xliff:g id="NUMBER_1">%s</xliff:g> notificações no grupo.</item>
+ <item quantity="one">Mais <xliff:g id="NUMBER_0">%s</xliff:g> notificação no grupo.</item>
</plurals>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Definições de notificação"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Definições do <xliff:g id="APP_NAME">%s</xliff:g>"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Pretende remover o utilizador?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Serão eliminados todos os dados e todas as aplicações deste utilizador."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Remover"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"A poupança de bateria está ligada"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Poupança de bateria ativada"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduz o desempenho e os dados de segundo plano"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desativar a poupança de bateria"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Desativar a Poupança de bateria"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"O(a) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vai começar a captar tudo o que é apresentado no ecrã."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Não mostrar de novo"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Limpar tudo"</string>
@@ -553,13 +551,13 @@
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Esta aplicação não tem categorias de notificação"</string>
<string name="notification_unblockable_desc" msgid="3561016061737896906">"Não é possível desativar as notificações desta aplicação"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="one">1 de <xliff:g id="NUMBER_0">%s</xliff:g> categoria de notificação desta aplicação</item>
<item quantity="other">1 de <xliff:g id="NUMBER_1">%s</xliff:g> categorias de notificação desta aplicação</item>
+ <item quantity="one">1 de <xliff:g id="NUMBER_0">%s</xliff:g> categoria de notificação desta aplicação</item>
</plurals>
<string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
<plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> e mais <xliff:g id="NUMBER_2">%3$d</xliff:g></item>
<item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> e mais <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
+ <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> e mais <xliff:g id="NUMBER_2">%3$d</xliff:g></item>
</plurals>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Controlos de notificações da aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> abertos"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Controlos de notificações da aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> fechados"</string>
@@ -574,16 +572,16 @@
<string name="snooze_undo" msgid="6074877317002985129">"ANULAR"</string>
<string name="snoozed_for_time" msgid="2390718332980204462">"Suspensa por <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<plurals name="snoozeHourOptions" formatted="false" msgid="2124335842674413030">
- <item quantity="one">%d hora</item>
<item quantity="other">%d horas</item>
+ <item quantity="one">%d hora</item>
</plurals>
<plurals name="snoozeMinuteOptions" formatted="false" msgid="4127251700591510196">
- <item quantity="one">%d minuto</item>
<item quantity="other">%d minutos</item>
+ <item quantity="one">%d minuto</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Utiliz. da bateria"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Poupança de bateria não disponível durante o carregamento"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Poupança de bateria"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Poupança de bateria não disponível durante o carregamento"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Poupança de bateria"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduz o desempenho e os dados de segundo plano"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Início"</string>
@@ -758,7 +756,8 @@
<string name="instant_apps" msgid="6647570248119804907">"Aplicações instantâneas"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"As Aplicações instantâneas não requerem instalação."</string>
<string name="app_info" msgid="6856026610594615344">"Informações da aplicação"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Aceder à Web"</string>
+ <!-- no translation found for go_to_web (2650669128861626071) -->
+ <skip />
<string name="mobile_data" msgid="7094582042819250762">"Dados móveis"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi desativado"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth desativado"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index ce457be..a7c3af1 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Bateria fraca"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> restantes"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> restantes. A Economia de bateria está ativada."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante(s). A Economia de bateria está ativada."</string>
<string name="invalid_charger" msgid="4549105996740522523">"O carregamento via USB não é suportado.\nUse apenas o carregador fornecido."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"O carregamento via USB não é suportado."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Use apenas o carregador fornecido."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Configurações"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Ativar a economia de bateria?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Ativar Economia de bateria?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Ativar"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Ativar a economia de bateria"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Ativar a Economia de bateria"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configurações"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Girar tela automaticamente"</string>
@@ -245,8 +245,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os dados foram pausados"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"O limite de dados que você definiu foi atingido. Você não está mais usando dados móveis.\n\nSe retomar o uso de dados, o serviço poderá ser cobrado."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem conexão à Internet"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Local definido por GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Solicitações de localização ativas"</string>
@@ -403,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Remover usuário?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Todos os apps e dados deste usuário serão excluídos."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Remover"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"A Economia de bateria está ativada"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Economia de bateria ativada"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduz o desempenho e os dados em segundo plano"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desativar a economia de bateria"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Desativar a Economia de bateria"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> começará a capturar tudo o que for exibido na tela."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Não mostrar novamente"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Limpar tudo"</string>
@@ -584,8 +582,8 @@
<item quantity="other">%d minutos</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Uso da bateria"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"O recurso \"Economia de bateria\" não fica disponível durante o carregamento"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Economia de bateria"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"A Economia de bateria não fica disponível durante o carregamento"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Economia de bateria"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduz o desempenho e os dados em segundo plano"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index c7822e0d..4392efe 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -35,14 +35,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificări"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Bateria este aproape descărcată"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Procent rămas din baterie: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Procent rămas din baterie: <xliff:g id="PERCENTAGE">%s</xliff:g>. Economisirea bateriei este activată."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Procent rămas din baterie: <xliff:g id="PERCENTAGE">%s</xliff:g>. Economisirea bateriei este activată."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Încărcarea USB nu este acceptată. \nUtilizați numai încărcătorul furnizat."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Încărcarea prin USB nu este acceptată."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Utilizați numai încărcătorul furnizat."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Setări"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Activați economisirea bateriei?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Activați economisirea bateriei?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Activați"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Activați economisirea bateriei"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Activați economisirea bateriei"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Setări"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rotire automată a ecranului"</string>
@@ -246,8 +246,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Conexiunea de date este întreruptă"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"A fost atinsă limita de date setată. Datele mobile nu mai sunt folosite.\n\nDacă reluați, este posibil să se aplice taxe pentru utilizarea datelor."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reluați"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Fără conex. internet"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectat"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Se caută GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Locație setată prin GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Solicitări locație active"</string>
@@ -405,9 +403,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Eliminați utilizatorul?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Toate aplicațiile și datele acestui utilizator vor fi șterse."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Eliminați"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Economisirea bateriei este activată"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Economisire baterie activată"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce performanța și datele de fundal"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Dezactivați economisirea bateriei"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Dezactivați economisirea bateriei"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> va începe să captureze tot ceea ce se afișează pe ecran."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Nu se mai afișează"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Ștergeți toate notificările"</string>
@@ -590,8 +588,8 @@
<item quantity="one">%d minut</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Utilizarea bateriei"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Economisirea bateriei nu este disponibilă pe durata încărcării"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Economisirea energiei"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Economisirea bateriei nu este disponibilă pe durata încărcării"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Economisirea bateriei"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce performanța și datele de fundal"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Butonul <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"La început"</string>
diff --git a/packages/SystemUI/res/values-ru/config.xml b/packages/SystemUI/res/values-ru/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-ru/config.xml
+++ b/packages/SystemUI/res/values-ru/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index f78c3bb..fd1d3be 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -36,14 +36,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Уведомления"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Батарея почти разряжена"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Осталось: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Осталось: <xliff:g id="PERCENTAGE">%s</xliff:g>. Включен режим энергосбережения."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Уровень заряда батареи: <xliff:g id="PERCENTAGE">%s</xliff:g>. Включен режим энергосбережения."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Зарядка через порт USB не поддерживается.\nИспользуйте только зарядное устройство из комплекта поставки."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Зарядка через USB не поддерживается."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Используйте только зарядное устройство, поставляемое в комплекте с устройством."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Настройки"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Включить режим энергосбережения?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Включить режим энергосбережения?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Включить"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Включить режим энергосбережения"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Включить режим энергосбережения"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Настройки"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Автоповорот экрана"</string>
@@ -53,15 +53,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Общий модем доступен через Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Настройка способов ввода"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Физическая клавиатура"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Открыть приложению \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" доступ к USB-устройству?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Открыть приложению \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" доступ к USB-устройству?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Запускать <xliff:g id="ACTIVITY">%1$s</xliff:g> при подключении этого USB-устройства?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Запускать <xliff:g id="ACTIVITY">%1$s</xliff:g> при подключении этого USB-аксессуара?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Предоставить приложению \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" доступ к устройству \"<xliff:g id="USB_DEVICE">%2$s</xliff:g>\"?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Предоставить приложению \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" доступ к устройству \"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>\"?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Открыть приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" для управления устройством \"<xliff:g id="USB_DEVICE">%2$s</xliff:g>\"?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Открыть приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" для управления устройством \"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>\"?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Приложения не поддерживают это USB-устройство. Подробнее о нем читайте здесь: <xliff:g id="URL">%1$s</xliff:g>."</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB-устройство"</string>
<string name="label_view" msgid="6304565553218192990">"Просмотр"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Использовать по умолчанию для этого USB-устройства"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Использовать по умолчанию для этого USB-аксессуара"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Запускать приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" при подключ. устройства \"<xliff:g id="USB_DEVICE">%2$s</xliff:g>\""</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Запускать приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" при подключ. устройства \"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>\""</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Отладка по USB"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Цифровой отпечаток ключа RSA:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Всегда разрешать отладку с этого компьютера"</string>
@@ -201,7 +201,7 @@
<string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Режим полета включен."</string>
<string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Режим полета отключен."</string>
<string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Режим полета включен."</string>
- <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Режим \"Не беспокоить\" включен. Будут показаны только важные оповещения."</string>
+ <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Режим \"Не беспокоить\" включен. Будут показаны только важные уведомления."</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"Не беспокоить, полная тишина."</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Не беспокоить – только будильник."</string>
<string name="accessibility_quick_settings_dnd" msgid="6607873236717185815">"Не беспокоить."</string>
@@ -247,8 +247,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Передача данных приостановлена"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Достигнут лимит мобильного трафика, и передача данных остановлена.\n\nЕсли вы возобновите передачу данных по мобильной сети, может взиматься плата."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Возобновить"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нет интернет-подключения"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi подключено"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Поиск GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Координаты по GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Есть активные запросы на определение местоположения"</string>
@@ -362,7 +360,7 @@
<string name="zen_silence_introduction_voice" msgid="3948778066295728085">"Этот режим заблокирует все звуки и вибрацию, в том числе для будильника, музыки, видео и игр. Вы сможете разговаривать по телефону."</string>
<string name="zen_silence_introduction" msgid="3137882381093271568">"В этом режиме будут отключены вибросигнал и все звуки (в том числе для будильника, музыкального проигрывателя, игр и видео)."</string>
<string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
- <string name="speed_bump_explanation" msgid="1288875699658819755">"Показать менее важные оповещения"</string>
+ <string name="speed_bump_explanation" msgid="1288875699658819755">"Показать менее важные уведомления"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Нажмите ещё раз, чтобы открыть"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Проведите вверх, чтобы разблокировать"</string>
<string name="do_disclosure_generic" msgid="5615898451805157556">"Этим устройством управляет ваша организация"</string>
@@ -407,9 +405,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Удалить аккаунт?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Все приложения и данные этого пользователя будут удалены."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Удалить"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Включен режим энергосбережения"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Режим энергосбережения включен"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Откл. фоновой передачи данных"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Отключить режим энергосбережения"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Отключить режим энергосбережения"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"Приложение <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> получит доступ к изображению на экране устройства."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Больше не показывать"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Очистить все"</string>
@@ -555,7 +553,7 @@
<string name="power_notification_controls_description" msgid="4372459941671353358">"С помощью этой функции вы можете устанавливать уровень важности уведомлений от 0 до 5 для каждого приложения.\n\n"<b>"Уровень 5"</b>\n"‒ Помещать уведомления в начало списка.\n‒ Показывать полноэкранные уведомления.\n‒ Показывать всплывающие уведомления.\nУровень 4\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Показывать всплывающие уведомления.\nУровень 3\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Не показывать всплывающие уведомления.\nУровень 2\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Не показывать всплывающие уведомления.\n‒ Не использовать звук и вибрацию.\nУровень 1\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Не показывать всплывающие уведомления.\n‒ Не использовать звук и вибрацию.\n‒ Не показывать на экране блокировки и в строке состояния.\n‒ Помещать уведомления в конец списка.\nУровень 0\n"<b></b>\n"‒ Блокировать все уведомления приложения."</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Уведомления"</string>
<string name="notification_channel_disabled" msgid="2139193533791840539">"Вы больше не будете получать эти уведомления"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"Категорий оповещений: <xliff:g id="NUMBER">%d</xliff:g>"</string>
+ <string name="notification_num_channels" msgid="2048144408999179471">"Категорий уведомлений: <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"В приложении нет категорий уведомлений"</string>
<string name="notification_unblockable_desc" msgid="3561016061737896906">"Уведомления этого приложения нельзя отключить"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
@@ -596,8 +594,8 @@
<item quantity="other">%d минуты</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Уровень заряда"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Режим энергосбережения нельзя включить во время зарядки"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Режим энергосбережения"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Режим энергосбережения нельзя включить во время зарядки"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Режим энергосбережения"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Ограничивает производительность и фоновую передачу данных"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Кнопка <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Главный экран"</string>
diff --git a/packages/SystemUI/res/values-si/config.xml b/packages/SystemUI/res/values-si/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-si/config.xml
+++ b/packages/SystemUI/res/values-si/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index bab0c6e..fd636ad 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"දැනුම්දීම්"</string>
<string name="battery_low_title" msgid="6456385927409742437">"බැටරිය අඩුය"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> ඉතිරිව තිබේ"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> ඉතිරිව තිබේ. බැටරිය සුරැකීම සක්රීයි."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> ඉතිරිව ඇත. බැටරි සුරැකුම ක්රියාත්මකයි."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB ආරෝපණය සහය නොදක්වයි.\nසපයන ලද ආරෝපකය පමණක් භාවිතා කරන්න."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB ආරෝපණය කිරීම සහාය නොදක්වයි."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"සපයන ලද අරෝපකය පමණක් භාවිතා කරන්න."</string>
<string name="battery_low_why" msgid="4553600287639198111">"සැකසීම්"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"බැටරි සුරැකීම සක්රිය කරන්නද?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"බැටරි සුරැකුම ක්රියාත්මක කරන්නද?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"ක්රියාත්මක කරන්න"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"බැටරි සුරැකීම සක්රිය කරන්න"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"බැටරි සුරැකුම ක්රියාත්මක කරන්න"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"සැකසීම්"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"ස්වයංක්රීයව-භ්රමණය වන තිරය"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"බ්ලූටූත් ටෙදර් කරා"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ආදාන ක්රම සකසන්න"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"භෞතික යතුරු පුවරුව"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"USB උපාංගය ප්රවේශ කිරීමට <xliff:g id="APPLICATION">%1$s</xliff:g> යෙදුමට අවසර දෙනවාද?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"USB මෙවලම ප්රවේශ කිරීමට <xliff:g id="APPLICATION">%1$s</xliff:g> යෙදුමට අවසර දෙනවාද?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"මෙම USB උපාංගය සම්බන්ධ විට <xliff:g id="ACTIVITY">%1$s</xliff:g> විවෘත කරන්නද?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"මෙම USB මෙවලමට සම්බන්ධ වී ඇති විට <xliff:g id="ACTIVITY">%1$s</xliff:g> විවෘත කරන්නද?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> හට <xliff:g id="USB_DEVICE">%2$s</xliff:g> වෙත පිවිසීමට ඉඩ දෙන්නද?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> හට <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> වෙත පිවිසීමට ඉඩ දෙන්නද?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> හැසිරවීමට <xliff:g id="APPLICATION">%1$s</xliff:g> විවෘත කරන්නද?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> හැසිරවීමට <xliff:g id="APPLICATION">%1$s</xliff:g> විවෘත කරන්නද?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"මෙම USB මෙවලම සමග ක්රියා කරන ස්ථාපිත යෙදුම් නොමැත. <xliff:g id="URL">%1$s</xliff:g> වලින් මෙම මෙවලම ගැන තව දැනගන්න"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB මෙවලම"</string>
<string name="label_view" msgid="6304565553218192990">"පෙනුම"</string>
- <string name="always_use_device" msgid="1450287437017315906">"මෙම USB උපාංගය සඳහා සුපුරුද්දෙන් භාවිතා කරන්න"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"මේ USB මෙවලම සඳහා සුපුරුද්දෙන් භාවිතා කරන්න."</string>
+ <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> සම්බන්ධ විට <xliff:g id="APPLICATION">%1$s</xliff:g> සැම විටම විවෘත කරන්න"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> සම්බන්ධ විට <xliff:g id="APPLICATION">%1$s</xliff:g> සැම විටම විවෘත කරන්න"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB නිදොස්කරණයට අවසර දෙනවද?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"මෙම පරිගණකයේ RSA යතුරු ඇඟිලි සටහන වන්නේ:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"සැම විටම මෙම පරිගණකයෙන් ඉඩ ලබා දෙන්න"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"දත්ත විරාම කර ඇත"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"ඔබ සැකසූ දත්ත සීමාව ළඟා වී ඇත. ඔබ තවදුරටත් ජංගම දත්ත භාවිත නොකරයි. \n\nඔබ නැවත ආරම්භ කළහොත්, දත්ත භාවිතය සඳහා ගාස්තු අදාළ විය හැකිය."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"නැවත පටන්ගන්න"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"අන්තර්ජාල සම්බන්ධතාවයක් නැත"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi සම්බන්ධිතයි"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS සඳහා සොයමින්"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS මඟින් ස්ථානය සකසා ඇත"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"පිහිටීම් ඉල්ලීම් සක්රියයි"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"පරිශීලකයා ඉවත් කරන්නද?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"මෙම පරිශීලකයාගේ සියලු යෙදුම් සහ දත්ත මකනු ඇත."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"ඉවත් කරන්න"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"බැටරිය සුරකින්නා සක්රීයයි"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"බැටරි සුරැකුම ක්රියාත්මකයි"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ක්රියාකාරිත්වය සහ පසුබිම් දත්ත අඩු කරන්න"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"බැටරි සුරැකීම අක්රිය කරන්න"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"බැටරි සුරැකුම ක්රියාවිරහිත කරන්න"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"ඔබගේ තීරයේ දර්ශනය වන සෑම දෙයම <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ලබාගැනීම ආරම්භ කරන ලදි."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"නැවත නොපෙන්වන්න"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"සියල්ල හිස් කරන්න"</string>
@@ -582,8 +580,8 @@
<item quantity="other">මිනිත්තු %d</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"බැටරි භාවිතය"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"ආරෝපණය අතරතුර බැටරි සුරැකුම ලබා ගත නොහැකිය"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"බැටරිය සුරකින්නා"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ආරෝපණය අතරතුර බැටරි සුරැකුම ලබා ගත නොහැකිය."</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"බැටරි සුරැකුම"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"ක්රියාකාරිත්වය සහ පසුබිම් දත්ත අඩු කරන්න"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> බොත්තම"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home යතුර"</string>
diff --git a/packages/SystemUI/res/values-sk/config.xml b/packages/SystemUI/res/values-sk/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-sk/config.xml
+++ b/packages/SystemUI/res/values-sk/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 4be2941..b7f5445 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -36,14 +36,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Upozornenia"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Batéria je takmer vybitá"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Zostáva <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Zostáva <xliff:g id="PERCENTAGE">%s</xliff:g>. Šetrič batérie je zapnutý."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Zostáva: <xliff:g id="PERCENTAGE">%s</xliff:g>. Šetrič batérie je zapnutý."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Nabíjanie pomocou rozhrania USB nie je podporované.\nPoužívajte iba nabíjačku, ktorá bola dodaná spolu so zariadením."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Nabíjanie prostredníctvom USB nie je podporované."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Používajte iba originálnu nabíjačku."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Nastavenia"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Zapnúť šetrič batérie?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Zapnúť šetrič batérie?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Zapnúť"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Zapnúť šetrič batérie"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Zapnúť šetrič batérie"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavenia"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi‑Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatické otočenie obrazovky"</string>
@@ -53,15 +53,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Zdieľané dátové pripojenie cez Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Nastavenie metód vstupu"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fyzická klávesnica"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Povoliť aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g> prístup k zariadeniu USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Povoliť aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g> prístup k periférnemu zariadeniu USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Chcete pri pripojení tohto zariadenia USB otvoriť aplikáciu <xliff:g id="ACTIVITY">%1$s</xliff:g>?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Chcete pri pripojení tohto periférneho zariadenia USB otvoriť aplikáciu <xliff:g id="ACTIVITY">%1$s</xliff:g>?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Povoliť aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g> prístup k zariadeniu <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Povoliť aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g> prístup k zariadeniu <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Otvoriť aplikáciu <xliff:g id="APPLICATION">%1$s</xliff:g> na použitie zariadenia <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Otvoriť aplikáciu <xliff:g id="APPLICATION">%1$s</xliff:g> na použitie zariadenia <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"S týmto zariad. USB nefunguje žiadna nainštal. aplikácia. Ďalšie informácie na <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Periférne zariadenie USB"</string>
<string name="label_view" msgid="6304565553218192990">"Zobraziť"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Pre toto zariadenie USB použiť ako predvolené"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Pre toto periférne zar. USB použiť ako predvolené"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Po pripojení zariadenia <xliff:g id="USB_DEVICE">%2$s</xliff:g> vždy otvoriť aplikáciu <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Po pripojení zariadenia <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> vždy otvoriť aplikáciu <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Povoliť ladenie USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Digitálny odtlačok RSA počítača je:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Vždy povoliť z tohto počítača"</string>
@@ -247,8 +247,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dáta sú pozastavené"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Dosiahli ste nastavený dátový limit. Už nepoužívate mobilné dátové pripojenie.\n\nAk ho znovu zapnete, môžu vám byť účtované poplatky za spotrebu dát."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Znova zapnúť"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Bez prip. na Internet"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi‑Fi: pripojené"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Vyhľadávanie satelitov GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Poloha nastavená pomocou GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Žiadosti o polohu sú aktívne"</string>
@@ -407,9 +405,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Odstrániť používateľa?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Všetky aplikácie a údaje tohto používateľa budú odstránené."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Odstrániť"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Šetrič batérie je zapnutý"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Šetrič batérie je zapnutý"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Obmedzí výkonnosť a prenos údajov na pozadí"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Vypnúť šetrič batérie"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Vypnúť šetrič batérie"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikácia <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> začne zaznamenávať všetok obsah zobrazený na vašej obrazovke."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Nabudúce nezobrazovať"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Vymazať všetko"</string>
@@ -596,8 +594,8 @@
<item quantity="one">%d minúta</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Využitie batérie"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Počas nabíjania nie je Šetrič batérie k dispozícii"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Šetrič batérie"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Počas nabíjania nie je Šetrič batérie k dispozícii"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Šetrič batérie"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Obmedzí výkonnosť a údaje na pozadí"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Tlačidlo <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Domov"</string>
diff --git a/packages/SystemUI/res/values-sl/config.xml b/packages/SystemUI/res/values-sl/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-sl/config.xml
+++ b/packages/SystemUI/res/values-sl/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 49cbdbf..5a00c53 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -36,14 +36,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Obvestila"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Akumulator je skoraj izpraznjen"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Še <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Še <xliff:g id="PERCENTAGE">%s</xliff:g>. Vklopljeno je varčevanje z energijo akumulatorja."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Še <xliff:g id="PERCENTAGE">%s</xliff:g>. Vklopljeno je varčevanje z energijo akumulatorja."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Polnjenje po povezavi USB ni podprto.\nUporabite priloženi polnilnik."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Polnjenje prek USB-ja ni podprto."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Uporabljajte samo priloženi polnilnik."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Nastavitve"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Želite vklopiti varčevanje z energijo akumulatorja?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Želite vklopiti varčevanje z energijo akumulatorja?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Vklopi"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Vklop varčevanja z energijo"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Vklop varčevanja z energijo akumulatorja"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavitve"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Samodejno zasukaj zaslon"</string>
@@ -53,15 +53,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Internetna povezava prek Bluetootha"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Nastavi načine vnosa"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fizična tipkovnica"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Želite aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> dovoliti dostop do naprave USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Želite dovoliti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> dostop do dodatka USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Želite, da se odpre <xliff:g id="ACTIVITY">%1$s</xliff:g>, ko priključite to napravo USB?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Želite, da se odpre <xliff:g id="ACTIVITY">%1$s</xliff:g>, ko priključite ta dodatek USB?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Ali aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> dovolite dostop do dodatka USB <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Ali aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> dovolite dostop do dodatka USB <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Želite odpreti aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g> za upravljanje dodatka USB <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Želite odpreti aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g> za upravljanje dodatka USB <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Namešč. prog. ne delujejo s tem dodatkom USB. Več o tem dodatku preberite na <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Dodatek USB"</string>
<string name="label_view" msgid="6304565553218192990">"Prikaži"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Privzeto uporabi za to napravo USB"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Privzeto uporabi za ta dodatek USB"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Ko je dodatek <xliff:g id="USB_DEVICE">%2$s</xliff:g> povezan, vedno odpri aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Ko je dodatek <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> povezan, vedno odpri aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Ali dovolite odpravljanje težav prek USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Računalnikov prstni odtis ključa RSA je:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Vedno dovoli iz tega računalnika"</string>
@@ -247,8 +247,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Prenos podatkov je zaustavljen"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Dosegli ste nastavljeno omejitev porabe podatkov. Prenosa podatkov v mobilnem omrežju ne uporabljate več.\n\nČe nadaljujete, lahko nastanejo stroški prenosa podatkov."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nadaljuj"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ni internetne povez."</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Iskanje GPS-a"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokacija nastavljena z GPS-om"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Aktivne zahteve za lokacijo"</string>
@@ -407,9 +405,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Želite odstraniti uporabnika?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Vse aplikacije in podatki tega uporabnika bodo izbrisani."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Odstrani"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Varčevanje z energijo akumulatorja je vklopljeno"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Varčevanje z energijo akumulatorja je vklopljeno"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Omeji zmogljivost delovanja in prenos podatkov v ozadju"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Izklop varčevanja z energijo akumulatorja"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Izklop varčevanja z energijo akumulatorja"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> bo začela zajemati vse, kar je prikazano na zaslonu."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Tega ne prikaži več"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Izbriši vse"</string>
@@ -596,8 +594,8 @@
<item quantity="other">%d minut</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Poraba akumulatorja"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Varčevanje z energijo akumulatorja med polnjenjem ni na voljo"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Varčevanje z energijo akumulatorja"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Varčevanje z energijo akumulatorja med polnjenjem ni na voljo"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Varčevanje z energijo akumulatorja"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Omeji zmogljivost delovanja in prenos podatkov v ozadju"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Gumb <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Začetek"</string>
diff --git a/packages/SystemUI/res/values-sq/config.xml b/packages/SystemUI/res/values-sq/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-sq/config.xml
+++ b/packages/SystemUI/res/values-sq/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 66d692c..801ee90 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Njoftimet"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Niveli i baterisë është i ulët"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Ka mbetur edhe <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Ka mbetur edhe <xliff:g id="PERCENTAGE">%s</xliff:g>. Kursimi i baterisë është i aktivizuar."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Ka mbetur edhe <xliff:g id="PERCENTAGE">%s</xliff:g>. \"Kursyesi i baterisë\" është i aktivizuar."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Ngarkuesi USB nuk mbështetet.\nPërdor vetëm ngarkuesin e dhënë."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Ngarkimi i USB-së nuk mbështetet."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Përdor vetëm ngarkuesin e dhënë."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Cilësimet"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Të aktivizohet kursimi i baterisë?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Të aktivizohet \"Kursyesi i baterisë\"?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Ndiz"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Aktivizo kursimin e baterisë"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Aktivizo \"Kursyesin e baterisë\""</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Cilësimet"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Ekran me rrotullim automatik"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"\"Bluetooth-i\" është i lidhur"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfiguro metodat e hyrjes"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Tastierë fizike"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Lejo aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g> të hyjë në pajisjen \"USB\"?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Lejo aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g> të hyjë në cilësimet e qasjes së USB-së?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Të hapet <xliff:g id="ACTIVITY">%1$s</xliff:g> kur pajisja USB të jetë lidhur?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Të hapet <xliff:g id="ACTIVITY">%1$s</xliff:g> kur ndihmësi i USB-së të jetë lidhur?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Të lejohet <xliff:g id="APPLICATION">%1$s</xliff:g> të ketë qasje te <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Të lejohet <xliff:g id="APPLICATION">%1$s</xliff:g> të ketë qasje te <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Të hapet <xliff:g id="APPLICATION">%1$s</xliff:g> për të përdorur <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Të hapet <xliff:g id="APPLICATION">%1$s</xliff:g> për të përdorur <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Asnjë aplikacion i instaluar nuk punon me këtë ndihmës USB-je. Mëso më shumë rreth këtij ndihmësi në <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Qasja në USB"</string>
<string name="label_view" msgid="6304565553218192990">"Pamje"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Përdor cilësimet e paracaktuara për këtë pajisje USB-je."</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Përdor cilësimet e paracaktuara për këtë ndihmës të USB-së."</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Hap gjithmonë <xliff:g id="APPLICATION">%1$s</xliff:g> kur lidhet <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Hap gjithmonë <xliff:g id="APPLICATION">%1$s</xliff:g> kur lidhet <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Të lejohet korrigjimi i USB-së?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Shenja e gishtit të tastit \"RSA\" së kompjuterit është:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Lejo gjithmonë nga ky kompjuter"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Të dhënat janë ndërprerë"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Kufiri i të dhënave që ke caktuar është arritur. Nuk po përdor më të dhënat celulare.\n\nNëse vazhdon, mund të zbatohen tarifa për përdorimin e të dhënave."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Rifillo"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nuk ka lidhje interneti"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi është i lidhur"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Po kërkon GPS-në"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Vendndodhja është caktuar nga GPS-ja"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Kërkesat për vendodhje janë aktive"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Të hiqet ky përdorues?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Të gjitha aplikacionet dhe të dhënat e këtij përdoruesi do të fshihen."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Hiqe"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Kursimi i baterisë është i aktivizuar"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"\"Kursyesi i baterisë\" është i aktivizuar"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Pakëson veprimtarinë dhe të dhënat në sfond"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Çaktivizo kursimin e baterisë"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Çaktivizo \"Kursyesin e baterisë\""</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> do të fillojë të regjistrojë çdo gjë që shfaqet në ekran."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Mos e shfaq sërish"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Pastroji të gjitha"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d minutë</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Përdorimi i baterisë"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"\"Kursyesi i baterisë\" nuk është i disponueshëm gjatë ngarkimit"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Kursyesi i baterisë"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"\"Kursyesi i baterisë\" nuk është i disponueshëm gjatë karikimit"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Kursyesi i baterisë"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Pakëson veprimtarinë dhe të dhënat në sfond"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Butoni <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Kreu"</string>
diff --git a/packages/SystemUI/res/values-sr/config.xml b/packages/SystemUI/res/values-sr/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-sr/config.xml
+++ b/packages/SystemUI/res/values-sr/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 97b9ce4..7a76d40 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -35,14 +35,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Обавештења"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Ниво напуњености батерије је низак"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Још <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Још <xliff:g id="PERCENTAGE">%s</xliff:g>. Укључена је штедња батерије."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Још <xliff:g id="PERCENTAGE">%s</xliff:g>. Уштеда батерије је укључена."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Пуњење преко USB-а није подржано.\nКористите само приложени пуњач."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Пуњење преко USB-а није подржано."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Користите само пуњач који сте добили."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Подешавања"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Желите ли да укључите штедњу батерије?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Желите ли да укључите Уштеду батерије?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Укључи"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Укључи штедњу батерије"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Укључи Уштеду батерије"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Подешавања"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Аутоматско ротирање екрана"</string>
@@ -52,15 +52,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Веза преко Bluetooth-а"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Подеси методе уноса"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Физичка тастатура"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Желите ли да дозволите апликацији <xliff:g id="APPLICATION">%1$s</xliff:g> да приступа USB уређају?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Желите ли да дозволите апликацији <xliff:g id="APPLICATION">%1$s</xliff:g> да приступа USB помоћном уређају?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Желите ли да се отвори <xliff:g id="ACTIVITY">%1$s</xliff:g> када се прикључи овај USB уређај?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Желите ли да се отвори <xliff:g id="ACTIVITY">%1$s</xliff:g> када се прикључи овај USB додатак?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Желите ли да дозволите да <xliff:g id="APPLICATION">%1$s</xliff:g> приступа уређају <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Желите ли да дозволите да <xliff:g id="APPLICATION">%1$s</xliff:g> приступа уређају <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Желите ли да отворите апликацију <xliff:g id="APPLICATION">%1$s</xliff:g> да бисте користили уређај <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Желите ли да отворите апликацију <xliff:g id="APPLICATION">%1$s</xliff:g> да бисте користили уређај <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Инсталиране апликације не функционишу са овим USB помоћним уређајем. Сазнајте више о њему на адреси <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB помоћни уређај"</string>
<string name="label_view" msgid="6304565553218192990">"Прикажи"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Користи подразумевано за овај USB уређај"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Користи подразумевано за овај USB додатак"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Увек отварај апликацију <xliff:g id="APPLICATION">%1$s</xliff:g> када је уређај <xliff:g id="USB_DEVICE">%2$s</xliff:g> повезан"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Увек отварај апликацију <xliff:g id="APPLICATION">%1$s</xliff:g> када је уређај <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> повезан"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Желите ли да дозволите отклањање USB грешака?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Дигитални отисак RSA кључа овог рачунара је:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Увек дозволи са овог рачунара"</string>
@@ -244,8 +244,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Подаци су паузирани"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Достигли се ограничење за податке које сте подесили. Више не користите мобилне податке.\n\nАко наставите, можда ће важити тарифе за потрошњу података."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Настави"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нема интернет везе"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi је повезан"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Тражи се GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Локацију је подесио GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Има активних захтева за локацију"</string>
@@ -403,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Желите ли да уклоните корисника?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Све апликације и подаци овог корисника ће бити избрисани."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Уклони"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Штедња батерије је укључена"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Уштеда батерије је укључена"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Смањује перформансе и позадинске податке"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Искључи штедњу батерије"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Искључи Уштеду батерије"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ће почети да снима све што се приказује на екрану."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Не приказуј поново"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Обриши све"</string>
@@ -588,8 +586,8 @@
<item quantity="other">%d минута</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Потрошња батерије"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Уштеда батерије није доступна током пуњења"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Уштеда батерије"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Уштеда батерије није доступна током пуњења"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Уштеда батерије"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Смањује перформансе и позадинске податке"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Дугме <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Тастер Почетна"</string>
diff --git a/packages/SystemUI/res/values-sv/config.xml b/packages/SystemUI/res/values-sv/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-sv/config.xml
+++ b/packages/SystemUI/res/values-sv/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 88b93aa..9b978e2 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meddelanden"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Lågt batteri"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> kvar"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> kvar. Batterisparläget är aktiverat."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> kvar. Batterisparläget är aktiverat."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Det går inte att ladda via USB.\nAnvänd endast den laddare som levererades med telefonen."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Det finns inget stöd för laddning via USB."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Använd endast den medföljande laddaren."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Inställningar"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Vill du aktivera batterisparläget?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Vill du aktivera batterisparläget?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Aktivera"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Aktivera batterisparläge"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Aktivera batterisparläget"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Inställningar"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rotera skärmen automatiskt"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Internetdelning via Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfigurera inmatningsmetoder"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fysiskt tangentbord"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Vill du tillåta att appen <xliff:g id="APPLICATION">%1$s</xliff:g> använder USB-enheten?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vill du tillåta att appen <xliff:g id="APPLICATION">%1$s</xliff:g> använder USB-tillbehöret?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vill du öppna <xliff:g id="ACTIVITY">%1$s</xliff:g> när den här USB-enheten ansluts?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Vill du öppna <xliff:g id="ACTIVITY">%1$s</xliff:g> när det här USB-tillbehöret ansluts?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Vill du ge <xliff:g id="APPLICATION">%1$s</xliff:g> åtkomst till <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Vill du ge <xliff:g id="APPLICATION">%1$s</xliff:g> åtkomst till <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Vill du öppna <xliff:g id="APPLICATION">%1$s</xliff:g> och hantera <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Vill du öppna <xliff:g id="APPLICATION">%1$s</xliff:g> och hantera <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Inga appar fungerar med det här USB-tillbehöret. Läs mer om det på <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB-tillbehör"</string>
<string name="label_view" msgid="6304565553218192990">"Visa"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Använd som standard för den här USB-enheten"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Använd som standard för det här USB-tillbehöret"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Öppna alltid <xliff:g id="APPLICATION">%1$s</xliff:g> när <xliff:g id="USB_DEVICE">%2$s</xliff:g> är ansluten"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Öppna alltid <xliff:g id="APPLICATION">%1$s</xliff:g> när <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> är ansluten"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Ska USB-felsökning tillåtas?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Fingeravtrycket för datorns RSA-nyckel är:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Tillåt alltid på den här datorn"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dataanvändningen har pausats"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Den angivna datagränsen har uppnåtts. Du använder inte längre mobildata.\n\nOm du fortsätter kan avgifter för dataanvändning tillkomma."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Återuppta"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen anslutning"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ansluten"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Sökning efter GPS pågår"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Platsen har identifierats av GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Det finns aktiva platsbegäranden"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Vill du ta bort användaren?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Alla appar och all data som tillhör den här användaren raderas."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Ta bort"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Batterisparläget har aktiverats"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Batterisparläget är aktiverat"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Minskar prestanda och bakgrundsdata"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Inaktivera batterisparläget"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Inaktivera batterisparläget"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tar en bild av allt som visas på skärmen."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Visa inte igen"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Rensa alla"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d minut</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Batteriförbrukning"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Batterisparläget är inte tillgängligt vid laddning"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Batterisparläge"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterisparläget är inte tillgängligt vid laddning"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Batterisparläge"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Minskar prestanda och bakgrundsdata"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Knappen <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Start"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 5853d93..aa7c3f7 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Arifa"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Betri inaisha"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Imebakisha <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Imebakisha <xliff:g id="PERCENTAGE">%s</xliff:g>. Kiokoa betri kimewashwa."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Imesalia <xliff:g id="PERCENTAGE">%s</xliff:g>. Umewasha Kiokoa Betri."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Chaji ya USB haihamiliwi.\n Tumia chaka iliyopeanwa."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Kuchaji kwa kutumia USB hakutumiki."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Tumia chaja iliyonunuliwa pamoja na kifaa pekee."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Mipangilio"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Ungependa kuwasha kiokoa betri?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Ungependa Kuwasha Kiokoa Betri?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Washa"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Washa kiokoa betri"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Washa Kiokoa Betri"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Mipangilio"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Skrini ijizungushe kiotomatiki"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data imesitishwa"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Umefikia kikomo cha data ulichoweka. Hutumii tena data ya simu.\n\nUkiendelea, huenda ukatozwa ada ya matumizi ya data."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Endelea"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Hakuna muunganisho wa mtandao"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Mtandao-hewa umeunganishwa"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Inatafuta GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Mahali pamewekwa na GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Maombi ya eneo yanatumika"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Je, ungependa kuondoa mtumiaji?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Programu na data yote ya mtumiaji huyu itafutwa."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Ondoa"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Kiokoa betri kimewashwa"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Kiokoa Betri kimewashwa"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Hupunguza utendaji na data ya chini chini"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Zima kiokoa betri"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Zima Kiokoa Betri"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> itaanza kupiga picha kila kitu kinachoonyeshwa kwenye skrini yako."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Usionyeshe tena"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Futa zote"</string>
@@ -582,8 +580,8 @@
<item quantity="one">Dakika %d</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Matumizi ya betri"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Kiokoa betri hakipatikani unapochaji betri"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Kiokoa betri"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Kiokoa Betri hakipatikani unapochaji betri"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Kiokoa Betri"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Hupunguza data ya chini chini na utendaji"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Kitufe cha <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Mwanzo"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 9972c73..4278d36 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -34,14 +34,17 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"அறிவிப்புகள்"</string>
<string name="battery_low_title" msgid="6456385927409742437">"பேட்டரி குறைவு"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> உள்ளது"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> உள்ளது. பேட்டரி சேமிப்பான் இயக்கத்தில் உள்ளது."</string>
+ <!-- no translation found for battery_low_percent_format_saver_started (7879389868952879166) -->
+ <skip />
<string name="invalid_charger" msgid="4549105996740522523">"USB மூலம் சார்ஜ் செய்வது ஆதரிக்கப்படவில்லை.\nவழங்கப்பட்ட சார்ஜரை மட்டும் பயன்படுத்தவும்."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB சார்ஜிங் ஆதரிக்கப்படவில்லை."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"வழங்கப்பட்ட சார்ஜரை மட்டும் பயன்படுத்துக."</string>
<string name="battery_low_why" msgid="4553600287639198111">"அமைப்பு"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"பேட்டரி சேமிப்பானை இயக்கவா?"</string>
+ <!-- no translation found for battery_saver_confirmation_title (2052100465684817154) -->
+ <skip />
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"இயக்கு"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"பேட்டரி சேமிப்பானை இயக்கு"</string>
+ <!-- no translation found for battery_saver_start_action (8187820911065797519) -->
+ <skip />
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"அமைப்பு"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"வைஃபை"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"திரையைத் தானாகச் சுழற்று"</string>
@@ -243,8 +246,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"தரவு இடைநிறுத்தப்பட்டது"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"நீங்கள் அமைத்த டேட்டா வரம்பை அடைந்துவிட்டீர்கள். இப்போது மொபைல் டேட்டாவைப் பயன்படுத்தவில்லை.\n\nமீண்டும் மொபைல் டேட்டாவைப் பயன்படுத்தத் தொடங்கினால், டேட்டா பயன்பாட்டிற்குக் கட்டணம் விதிக்கப்படலாம்."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"மீண்டும் தொடங்கு"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"இணைய இணைப்பு இல்லை"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"வைஃபை இணைக்கப்பட்டது"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS ஐத் தேடுகிறது"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS அமைத்த இருப்பிடம்"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"இருப்பிடக் கோரிக்கைகள் இயக்கப்பட்டன"</string>
@@ -401,9 +402,11 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"பயனரை அகற்றவா?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"இந்தப் பயனரின் எல்லா பயன்பாடுகளும் தரவும் நீக்கப்படும்."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"அகற்று"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"பேட்டரி சேமிப்பான் இயக்கத்தில் உள்ளது"</string>
+ <!-- no translation found for battery_saver_notification_title (8614079794522291840) -->
+ <skip />
<string name="battery_saver_notification_text" msgid="820318788126672692">"செயல்திறனையும் பின்புலத் தரவையும் குறைக்கிறது"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"பேட்டரி சேமிப்பானை முடக்கு"</string>
+ <!-- no translation found for battery_saver_notification_action_text (132118784269455533) -->
+ <skip />
<string name="media_projection_dialog_text" msgid="3071431025448218928">"திரையில் காட்டப்படும் அனைத்தையும் <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> படமெடுக்கும்."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"மீண்டும் காட்டாதே"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"எல்லாவற்றையும் அழி"</string>
@@ -582,8 +585,8 @@
<item quantity="one">%d நிமிடம்</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"பேட்டரி பயன்பாடு"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"சார்ஜ் செய்யும் போது பேட்டரி சேமிப்பானைப் பயன்படுத்த முடியாது"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"பேட்டரி சேமிப்பான்"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"சார்ஜ் செய்யும் போது பேட்டரி சேமிப்பானைப் பயன்படுத்த முடியாது"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"பேட்டரி சேமிப்பான்"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"செயல்திறனையும் பின்புலத்தில் தரவு செயலாக்கப்படுவதையும் குறைக்கும்"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> பொத்தான்"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"ஹோம்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 0652de9..60fe59a 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -34,14 +34,17 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"నోటిఫికేషన్లు"</string>
<string name="battery_low_title" msgid="6456385927409742437">"బ్యాటరీ తక్కువగా ఉంది"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> మిగిలి ఉంది"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> మిగిలి ఉంది. బ్యాటరీ సేవర్ ఆన్లో ఉంది."</string>
+ <!-- no translation found for battery_low_percent_format_saver_started (7879389868952879166) -->
+ <skip />
<string name="invalid_charger" msgid="4549105996740522523">"USB ఛార్జింగ్కు మద్దతు లేదు.\nఅందించిన ఛార్జర్ను మాత్రమే ఉపయోగించండి."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB ఛార్జింగ్కి మద్దతు లేదు."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"అందించిన ఛార్జర్ను మాత్రమే ఉపయోగించండి."</string>
<string name="battery_low_why" msgid="4553600287639198111">"సెట్టింగ్లు"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"బ్యాటరీ సేవర్ను ఆన్ చేయాలా?"</string>
+ <!-- no translation found for battery_saver_confirmation_title (2052100465684817154) -->
+ <skip />
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"ఆన్ చేయి"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"బ్యాటరీ సేవర్ను ఆన్ చేయి"</string>
+ <!-- no translation found for battery_saver_start_action (8187820911065797519) -->
+ <skip />
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"సెట్టింగ్లు"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"స్క్రీన్ను స్వయంచాలకంగా తిప్పండి"</string>
@@ -51,21 +54,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"బ్లూటూత్ టీథర్ చేయబడింది"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ఇన్పుట్ పద్ధతులను సెటప్ చేయండి"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"భౌతిక కీబోర్డ్"</string>
- <!-- no translation found for usb_device_permission_prompt (1825685909587559679) -->
- <skip />
- <!-- no translation found for usb_accessory_permission_prompt (2465531696941369047) -->
- <skip />
- <!-- no translation found for usb_device_confirm_prompt (7440562274256843905) -->
- <skip />
- <!-- no translation found for usb_accessory_confirm_prompt (4333670517539993561) -->
- <skip />
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ని యాక్సెస్ చేయడానికి <xliff:g id="APPLICATION">%1$s</xliff:g>ని అనుమతించాలా?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>ని యాక్సెస్ చేయడానికి <xliff:g id="APPLICATION">%1$s</xliff:g>ని అనుమతించాలా?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ని నిర్వహించడానికి <xliff:g id="APPLICATION">%1$s</xliff:g>ని తెరవాలా?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>ని నిర్వహించడానికి <xliff:g id="APPLICATION">%1$s</xliff:g>ని తెరవాలా?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ఈ USB ఉపకరణంతో ఇన్స్టాల్ చేయబడిన అనువర్తనాలు ఏవీ పని చేయవు. ఈ ఉపకరణం గురించి <xliff:g id="URL">%1$s</xliff:g>లో మరింత తెలుసుకోండి"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB ఉపకరణం"</string>
<string name="label_view" msgid="6304565553218192990">"వీక్షించండి"</string>
- <!-- no translation found for always_use_device (4015357883336738417) -->
- <skip />
- <!-- no translation found for always_use_accessory (3257892669444535154) -->
- <skip />
+ <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> కనెక్ట్ అయి ఉన్న ఎల్లప్పుడూ <xliff:g id="APPLICATION">%1$s</xliff:g>ని తెరవండి"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> కనెక్ట్ అయి ఉన్న ఎల్లప్పుడూ <xliff:g id="APPLICATION">%1$s</xliff:g>ని తెరవండి"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB డీబగ్గింగ్ను అనుమతించాలా?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"ఇది కంప్యూటర్ యొక్క RSA కీ వేలిముద్ర:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"ఈ కంప్యూటర్ నుండి ఎల్లప్పుడూ అనుమతించు"</string>
@@ -249,8 +246,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"డేటా పాజ్ చేయబడింది"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"మీరు సెట్ చేసిన డేటా పరిమితిని చేరుకున్నారు. మీరు ఇప్పుడు మొబైల్ డేటాను ఉపయోగించడం లేదు.\n\nమీరు పునఃప్రారంభిస్తే, డేటా వినియోగానికి ఛార్జీలు చెల్లించాల్సి రావచ్చు."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"పునఃప్రారంభించు"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ఇంటర్నెట్ కనెక్షన్ లేదు"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi కనెక్ట్ చేయబడింది"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS కోసం శోధిస్తోంది"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"స్థానం GPS ద్వారా సెట్ చేయబడింది"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"స్థాన అభ్యర్థనలు సక్రియంగా ఉన్నాయి"</string>
@@ -407,9 +402,11 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"వినియోగదారుని తీసివేయాలా?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"ఈ వినియోగదారుకు సంబంధించిన అన్ని అనువర్తనాలు మరియు డేటా తొలగించబడతాయి."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"తీసివేయి"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"బ్యాటర్ సేవర్ ఆన్ చేయబడింది"</string>
+ <!-- no translation found for battery_saver_notification_title (8614079794522291840) -->
+ <skip />
<string name="battery_saver_notification_text" msgid="820318788126672692">"పనితీరుని మరియు నేపథ్య డేటాను తగ్గిస్తుంది"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"బ్యాటరీ సేవర్ను ఆఫ్ చేయి"</string>
+ <!-- no translation found for battery_saver_notification_action_text (132118784269455533) -->
+ <skip />
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> మీ స్క్రీన్పై కనిపించే ప్రతిదాన్ని క్యాప్చర్ చేయడం ప్రారంభిస్తుంది."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"మళ్లీ చూపవద్దు"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"అన్నీ క్లియర్ చేయండి"</string>
@@ -588,8 +585,8 @@
<item quantity="one">%d నిమిషం</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"బ్యాటరీ వినియోగం"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"ఛార్జ్ అవుతున్న సమయంలో బ్యాటరీ సేవర్ అందుబాటులో లేదు"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"బ్యాటరీ సేవర్"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ఛార్జ్ అవుతున్న సమయంలో బ్యాటరీ సేవర్ అందుబాటులో ఉండదు"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"బ్యాటరీ సేవర్"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"పనితీరుని మరియు నేపథ్య డేటాను తగ్గిస్తుంది"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"బటన్ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-th/config.xml b/packages/SystemUI/res/values-th/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-th/config.xml
+++ b/packages/SystemUI/res/values-th/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 5f577f6..3dc4513 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"การแจ้งเตือน"</string>
<string name="battery_low_title" msgid="6456385927409742437">"แบตเตอรี่เหลือน้อย"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"เหลืออีก <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"เหลืออีก <xliff:g id="PERCENTAGE">%s</xliff:g> เปิดประหยัดแบตเตอรี่"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"แบตเตอรี่เหลือ <xliff:g id="PERCENTAGE">%s</xliff:g> เปิดโหมดประหยัดแบตเตอรี่อยู่"</string>
<string name="invalid_charger" msgid="4549105996740522523">"ไม่สนับสนุนการชาร์จแบบ USB\nใช้เฉพาะที่ชาร์จที่ให้มาเท่านั้น"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"ไม่รองรับการชาร์จผ่าน USB"</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"ใช้เฉพาะที่ชาร์จที่ให้มา"</string>
<string name="battery_low_why" msgid="4553600287639198111">"การตั้งค่า"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"เปิดโหมดประหยัดแบตเตอรี่ไหม"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"เปิดโหมดประหยัดแบตเตอรี่ใช่ไหม"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"เปิด"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"เปิดโหมดประหยัดแบตเตอรี่"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"เปิดโหมดประหยัดแบตเตอรี่"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"การตั้งค่า"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WiFi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"หมุนหน้าจออัตโนมัติ"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"บลูทูธที่ปล่อยสัญญาณ"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ตั้งค่าวิธีการป้อนข้อมูล"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"แป้นพิมพ์บนเครื่อง"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"อนุญาตให้แอปพลิเคชัน <xliff:g id="APPLICATION">%1$s</xliff:g> เข้าถึงอุปกรณ์ USB นี้หรือไม่"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"อนุญาตให้แอปพลิเคชัน <xliff:g id="APPLICATION">%1$s</xliff:g> เข้าถึงอุปกรณ์เสริม USB นี้หรือไม่"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"เปิด <xliff:g id="ACTIVITY">%1$s</xliff:g> เมื่อมีการเชื่อมต่ออุปกรณ์ USB นี้หรือไม่"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"เปิด <xliff:g id="ACTIVITY">%1$s</xliff:g> เมื่อมีการเชื่อมต่ออุปกรณ์เสริม USB นี้หรือไม่"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"อนุญาตให้ <xliff:g id="APPLICATION">%1$s</xliff:g> เข้าถึง <xliff:g id="USB_DEVICE">%2$s</xliff:g> ไหม"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"อนุญาตให้ <xliff:g id="APPLICATION">%1$s</xliff:g> เข้าถึง <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ไหม"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"เปิด <xliff:g id="APPLICATION">%1$s</xliff:g> เพื่อจัดการ <xliff:g id="USB_DEVICE">%2$s</xliff:g> ไหม"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"เปิด <xliff:g id="APPLICATION">%1$s</xliff:g> เพื่อจัดการ <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ไหม"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"แอปพลิเคชันที่ติดตั้งใช้กับอุปกรณ์ USB นี้ไม่ได้ เรียนรู้เพิ่มเติมเกี่ยวกับอุปกรณ์เสริมนี้ที่ <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"อุปกรณ์เสริม USB"</string>
<string name="label_view" msgid="6304565553218192990">"ดู"</string>
- <string name="always_use_device" msgid="1450287437017315906">"ใช้ค่าเริ่มต้นสำหรับอุปกรณ์ USB นี้"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"ใช้ค่าเริ่มต้นสำหรับอุปกรณ์เสริม USB นี้"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"เปิด <xliff:g id="APPLICATION">%1$s</xliff:g> ทุกครั้งเมื่อเชื่อมต่อกับ <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"เปิด <xliff:g id="APPLICATION">%1$s</xliff:g> ทุกครั้งเมื่อเชื่อมต่อกับ <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"อนุญาตให้แก้ไขข้อบกพร่อง USB หรือไม่"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"ลายนิ้วมือหลัก RSA ของคอมพิวเตอร์คือ:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"อนุญาตจากคอมพิวเตอร์เครื่องนี้เสมอ"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"หยุดการใช้ข้อมูลชั่วคราวแล้ว"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"คุณใช้อินเทอร์เน็ตถึงปริมาณที่กำหนดไว้แล้ว คุณไม่ได้ใช้อินเทอร์เน็ตมือถือแล้วในขณะนี้\n\nหากใช้ต่อ อาจมีการเรียกเก็บค่าบริการอินเทอร์เน็ต"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ใช้ต่อ"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ไม่มีอินเทอร์เน็ต"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"เชื่อมต่อ WiFi แล้ว"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"กำลังค้นหา GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"ตำแหน่งที่กำหนดโดย GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"คำขอตำแหน่งที่มีการใช้งาน"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"นำผู้ใช้ออกใช่ไหม"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"แอปและข้อมูลทั้งหมดของผู้ใช้นี้จะถูกลบ"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"นำออก"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"เปิดโหมดประหยัดแบตเตอรี่อยู่"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"เปิดโหมดประหยัดแบตเตอรี่อยู่"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ลดการใช้แบตเตอรี่และข้อมูลแบ็กกราวด์"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ปิดโหมดประหยัดแบตเตอรี่"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"ปิดโหมดประหยัดแบตเตอรี่"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> จะเริ่มจับภาพทุกอย่างที่แสดงบนหน้าจอ"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"ไม่ต้องแสดงข้อความนี้อีก"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"ล้างทั้งหมด"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d นาที</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"การใช้งานแบตเตอรี่"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"ไม่สามารถใช้โหมดประหยัดแบตเตอรี่ระหว่างการชาร์จ"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"โหมดประหยัดแบตเตอรี่"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ไม่สามารถใช้โหมดประหยัดแบตเตอรี่ระหว่างการชาร์จ"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"โหมดประหยัดแบตเตอรี่"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"ลดประสิทธิภาพการทำงานและข้อมูลแบ็กกราวด์"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"ปุ่ม <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-tl/config.xml b/packages/SystemUI/res/values-tl/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-tl/config.xml
+++ b/packages/SystemUI/res/values-tl/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index fa79f7c..f8f9159 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Mga Notification"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Mahina na ang baterya"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira. Naka-on ang battery saver."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira. Naka-on ang Pangtipid sa Baterya."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Hindi sinusuportahan ang pag-charge sa USB.\nGamitin lang ang ibinigay na charger."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Hindi sinusuportahan ang pagtsa-charge gamit ang USB."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Gamitin lang ang ibinigay na charger."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Mga Setting"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"I-on ang pagtitipid ng baterya?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"I-on ang Pangtipid sa Baterya?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"I-on"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"I-on ang pagtitipid ng baterya"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"I-on ang Pangtipid sa Baterya"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Mga Setting"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"I-auto rotate ang screen"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Na-tether ang bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"I-set up paraan ng pag-input"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Aktwal na keyboard"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Payagan ang app na <xliff:g id="APPLICATION">%1$s</xliff:g> na i-access ang USB device?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Payagan ang app na <xliff:g id="APPLICATION">%1$s</xliff:g> na i-access ang USB accessory?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Buksan ang <xliff:g id="ACTIVITY">%1$s</xliff:g> kapag nakakonekta ang USB device na ito?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Buksan ang <xliff:g id="ACTIVITY">%1$s</xliff:g> kapag nakakonekta ang accessory na USB na ito?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Payagan ang <xliff:g id="APPLICATION">%1$s</xliff:g> na ma-access ang <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Payagan ang <xliff:g id="APPLICATION">%1$s</xliff:g> na ma-access ang <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Buksan ang <xliff:g id="APPLICATION">%1$s</xliff:g> upang pamahalaan ang <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Buksan ang <xliff:g id="APPLICATION">%1$s</xliff:g> upang pamahalaan ang <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Wala sa mga na-install na app ang gumagana sa USB accessory na ito. Matuto nang higit pa tungkol sa accessory na ito sa <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB accessory"</string>
<string name="label_view" msgid="6304565553218192990">"Tingnan"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Gamitin bilang default para sa USB device"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Gamitin bilang default sa USB accessory na ito"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Palaging buksan ang <xliff:g id="APPLICATION">%1$s</xliff:g> kapag nakakonekta ang <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Palaging buksan ang <xliff:g id="APPLICATION">%1$s</xliff:g> kapag nakakonekta ang <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Payagan ang pag-debug ng USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Ang RSA key fingerprint ng computer ay:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Palaging payagan mula sa computer na ito"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Naka-pause ang data"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Naabot na ang itinakda mong limitasyon ng data. Hindi ka na gumagamit ng mobile data.\n\nKung magpapatuloy ka, maaaring may mga singil sa paggamit ng data."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Ipagpatuloy"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Walang koneksyon sa Internet"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"nakakonekta ang Wi-Fi"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Naghahanap ng GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasyong itinatakda ng GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Aktibo ang mga kahilingan ng lokasyon"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Gusto mo bang alisin ang user?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Made-delete ang lahat ng app at data ng user na ito."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Alisin"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Naka-on ang tagatipid ng baterya"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Naka-on ang Pangtipid sa Baterya"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Binabawasan ang performance at data sa background"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"I-off ang pagtitipid ng baterya"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"I-off ang Pangtipid sa Baterya"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"Sisimulan ng i-capture ng <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ang lahat ng ipinapakita sa iyong screen."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Huwag ipakitang muli"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"I-clear lahat"</string>
@@ -582,8 +580,8 @@
<item quantity="other">%d na minuto</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Paggamit ng baterya"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Hindi available ang pangtipid sa baterya kapag nagcha-charge"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Pangtipid sa baterya"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Hindi available ang Pangtipid sa Baterya kapag nagcha-charge"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Pangtipid sa Baterya"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Binabawasan ang performance at data sa background"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Button na <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-tr/config.xml b/packages/SystemUI/res/values-tr/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-tr/config.xml
+++ b/packages/SystemUI/res/values-tr/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 3a5ab8c..2499645 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Bildirimler"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Pil gücü düşük"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> kaldı"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> kaldı. Pil tasarrufu açık."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> kaldı. Pil Tasarrufu açık."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB üzerinden şarj desteklenmiyor.\nYalnızca ürünle birlikte verilen şarj cihazını kullanın."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB şarjı desteklenmiyor."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Yalnızca ürünle birlikte verilen şarj cihazını kullanın."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Ayarlar"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Pil tasarrufu açılsın mı?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Pil Tasarrufu açılsın mı?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Aç"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Pil tasarrufunu aç"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Pil Tasarrufu\'nu aç"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ayarlar"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Kablosuz"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Ekranı otomatik döndür"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth paylaşımı tamam"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Giriş yöntemlerini ayarla"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fiziksel klavye"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasının USB cihazına erişmesine izin verilsin mi?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasının USB aksesuarına erişmesine izin verilsin mi?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Bu USB cihaz bağlandığında <xliff:g id="ACTIVITY">%1$s</xliff:g> açılsın mı?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Bu USB aksesuarı bağlandığında <xliff:g id="ACTIVITY">%1$s</xliff:g> açılsın mı?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasının <xliff:g id="USB_DEVICE">%2$s</xliff:g> cihazına erişmesine izin verilsin mi?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasının <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> aksesuarına erişmesine izin verilsin mi?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> cihazını işlemek için <xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması açılsın mı?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> aksesuarını işlemek için <xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması açılsın mı?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Bu USB aksesuarıyla çalışan yüklü uygulama yok. Bu aksesuar hakkında bilgi içn: <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB aksesuarı"</string>
<string name="label_view" msgid="6304565553218192990">"Görüntüle"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Bu USB cihazı için varsayılan olarak kullan"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Bu USB aksesuar için varsayılan olarak kullan"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> bağlandığında <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasını her zaman aç"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> bağlandığında <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasını her zaman aç"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB hata ayıklamasına izin verilsin mi?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Bilgisayarın RSA anahtarı parmak izi:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Bu bilgisayardan her zaman izin ver"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Veri kullanımı duraklatıldı"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Ayarladığınız veri limitine ulaşıldı. Artık mobil veri kullanmıyorsunuz.\n\nDevam ettirirseniz veri kullanımı için sizden ödeme alınabilir."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Devam ettir"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"İnternet bağlantısı yok"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Kablosuz bağlandı"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS aranıyor"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Konum GPS ile belirlendi"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Konum bilgisi istekleri etkin"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Kullanıcı kaldırılsın mı?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Bu kullanıcının tüm uygulamaları ve verileri silinecek."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Kaldır"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Pil tasarrufu açık"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Pil Tasarrufu açık"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Performansı ve arka plan verilerini azaltır"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Pil tasarrufunu kapat"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Pil Tasarrufu\'nu kapat"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>, ekranınızda görüntülenen her şeyi kaydetmeye başlayacak."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Bir daha gösterme"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Tümünü temizle"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d dakika</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Pil kullanımı"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Şarj sırasında Pil tasarrufu özelliği kullanılamaz"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Pil tasarrufu"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Şarj sırasında Pil Tasarrufu özelliği kullanılamaz"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Pil Tasarrufu"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Performansı ve arka plan verilerini azaltır"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> düğmesi"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-uk/config.xml b/packages/SystemUI/res/values-uk/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-uk/config.xml
+++ b/packages/SystemUI/res/values-uk/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 1e3ebb2..95cd2d0 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -36,14 +36,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Сповіщення"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Низький рівень заряду акумулятора"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Залишилося <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Залишилося <xliff:g id="PERCENTAGE">%s</xliff:g>. Увімкнено режим енергозбереження."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Залишилося <xliff:g id="PERCENTAGE">%s</xliff:g>. Увімкнено режим економії заряду акумулятора."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Заряджання USB не підтримується.\nВикористовуйте лише наданий у комплекті зарядний пристрій."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Заряджання через USB не підтримується."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Використовуйте лише зарядний пристрій, який постачається в комплекті."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Налаштування"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Увімкнути режим енергозбереження?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Увімкнути режим економії заряду акумулятора?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Увімкнути"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Увімкнути режим енергозбереження"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Увімкнути режим економії заряду акумулятора"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Налаштування"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Повертати екран автоматично"</string>
@@ -53,15 +53,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Створено прив\'язку Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Налаштувати методи введення"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Фізична клавіатура"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Надати програмі <xliff:g id="APPLICATION">%1$s</xliff:g> доступ до пристрою USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Надати програмі <xliff:g id="APPLICATION">%1$s</xliff:g> доступ до аксесуара USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Відкривати \"<xliff:g id="ACTIVITY">%1$s</xliff:g>\", коли під’єднано пристрій USB?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Відкривати \"<xliff:g id="ACTIVITY">%1$s</xliff:g>\", коли під’єднано аксесуар USB?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Надати додатку <xliff:g id="APPLICATION">%1$s</xliff:g> доступ до такого аксесуара: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Надати додатку <xliff:g id="APPLICATION">%1$s</xliff:g> доступ до такого аксесуара: <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Відкрити додаток <xliff:g id="APPLICATION">%1$s</xliff:g>, щоб використовувати такий аксесуар: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Відкрити додаток <xliff:g id="APPLICATION">%1$s</xliff:g>, щоб використовувати такий аксесуар: <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Установлені прогр. не працюють із цим аксесуаром USB. Більше про цей аксесуар: <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Пристрій USB"</string>
<string name="label_view" msgid="6304565553218192990">"Переглянути"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Використовувати за умовчанням для пристрою USB"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Використовувати за умовчанням для аксесуара USB"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Завжди відкривати додаток <xliff:g id="APPLICATION">%1$s</xliff:g>, коли під’єднано такий аксесуар: <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Завжди відкривати додаток <xliff:g id="APPLICATION">%1$s</xliff:g>, коли під’єднано такий аксесуар: <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Дозволити налагодження USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Цифровий відбиток ключа RSA комп’ютера:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Завжди дозволяти з цього комп’ютера"</string>
@@ -247,8 +247,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Передавання даних призупинено"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Досягнуто ліміту мобільного трафіку. Ви його більше не витрачаєте.\n\nЯкщо ви продовжите, може стягуватися плата за використання трафіку."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Відновити"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Немає з’єднання"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi під’єднано"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Виконується пошук GPS-сигналу"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Місцезнаходження встановлено за допомогою GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Запити про місцезнаходження активні"</string>
@@ -407,9 +405,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Видалити користувача?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Усі додатки й дані цього користувача буде видалено."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Видалити"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Режим енергозбереження ввімкнено"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Режим економії заряду акумулятора ввімкнено"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Знижується продуктивність і обмежуються фонові дані"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Вимкнути режим енергозбереження"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Вимкнути режим економії заряду акумулятора"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> отримає доступ до всіх даних, які відображаються на вашому екрані."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Більше не показувати"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Очистити все"</string>
@@ -596,8 +594,8 @@
<item quantity="other">%d хвилини</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Використання заряду"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Режим економії заряду акумулятора не працює під час заряджання"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Режим економії заряду акумулятора"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Режим енергозбереження не можна ввімкнути під час заряджання"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Режим енергозбереження"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Знижується продуктивність і обмежується обмін даними у фоновому режимі"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Кнопка <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
@@ -772,7 +770,8 @@
<string name="instant_apps" msgid="6647570248119804907">"Додатки з миттєвим запуском"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Додатки з миттєвим запуском не потрібно встановлювати."</string>
<string name="app_info" msgid="6856026610594615344">"Про додаток"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Перейти на веб-сайт"</string>
+ <!-- no translation found for go_to_web (2650669128861626071) -->
+ <skip />
<string name="mobile_data" msgid="7094582042819250762">"Мобільний трафік"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi вимкнено"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth вимкнено"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 68db1bf..04bd340 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -34,14 +34,17 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"اطلاعات"</string>
<string name="battery_low_title" msgid="6456385927409742437">"بیٹری کم ہے"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی ہے"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی ہے۔ بیٹری سیور آن ہے۔"</string>
+ <!-- no translation found for battery_low_percent_format_saver_started (7879389868952879166) -->
+ <skip />
<string name="invalid_charger" msgid="4549105996740522523">"USB چارجنگ تعاون یافتہ نہیں ہے.\nصرف فراہم کردہ چارجر کا ہی استعمال کریں۔"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB چارجنگ تعاون یافتہ نہیں ہے۔"</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"صرف فراہم کردہ چارجر استعمال کریں۔"</string>
<string name="battery_low_why" msgid="4553600287639198111">"ترتیبات"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"بیٹری کی بچت آن کریں؟"</string>
+ <!-- no translation found for battery_saver_confirmation_title (2052100465684817154) -->
+ <skip />
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"آن کریں"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"بیٹری کی بچت آن کریں"</string>
+ <!-- no translation found for battery_saver_start_action (8187820911065797519) -->
+ <skip />
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ترتیبات"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"سکرین کو خودکار طور پر گھمائیں"</string>
@@ -51,21 +54,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"بلوٹوتھ مربوط کر دیا گیا"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ان پٹ کے طریقوں کو ترتیب دیں"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"طبعی کی بورڈ"</string>
- <!-- no translation found for usb_device_permission_prompt (1825685909587559679) -->
- <skip />
- <!-- no translation found for usb_accessory_permission_prompt (2465531696941369047) -->
- <skip />
- <!-- no translation found for usb_device_confirm_prompt (7440562274256843905) -->
- <skip />
- <!-- no translation found for usb_accessory_confirm_prompt (4333670517539993561) -->
- <skip />
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> کو <xliff:g id="USB_DEVICE">%2$s</xliff:g> تک رسائی حاصل کرنے کی اجازت دیں؟"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> کو <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> تک رسائی حاصل کرنے کی اجازت دیں؟"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ہینڈل کرنے کیلئے <xliff:g id="APPLICATION">%1$s</xliff:g> کھولیں؟"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ہینڈل کرنے کیلئے <xliff:g id="APPLICATION">%1$s</xliff:g> کھولیں؟"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"اس USB لوازم کے ساتھ کوئی انسٹال کردہ ایپس کام نہیں کرتی ہیں۔ <xliff:g id="URL">%1$s</xliff:g> پر مزید جانیں"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB لوازم"</string>
<string name="label_view" msgid="6304565553218192990">"دیکھیں"</string>
- <!-- no translation found for always_use_device (4015357883336738417) -->
- <skip />
- <!-- no translation found for always_use_accessory (3257892669444535154) -->
- <skip />
+ <string name="always_use_device" msgid="4015357883336738417">"ہمیشہ <xliff:g id="USB_DEVICE">%2$s</xliff:g> کے منسلک ہونے پر ہی <xliff:g id="APPLICATION">%1$s</xliff:g> کھولیں"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"ہمیشہ <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> کے منسلک ہونے پر ہی <xliff:g id="APPLICATION">%1$s</xliff:g> کھولیں"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB ڈیبگ کرنے کی اجازت دیں؟"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"کمپیوٹر کے RSA کا کلیدی فنگر پرنٹ ہے:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"اس کمپیوٹر سے ہمیشہ اجازت دیں"</string>
@@ -249,8 +246,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ڈیٹا موقوف کر دیا گیا"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"ڈیٹا کا استعمال آپ کی مقرر کردہ حد کو پہنچ چکا ہے۔ اب آپ موبائل ڈیٹا کا استعمال نہیں کر رہے ہیں۔\n\nاگر آپ دوبارہ شروع کرتے ہیں تو ڈیٹا استعمال کیلئے چارجز لاگو ہو سکتے ہیں۔"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"دوبارہ شروع کریں"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"کوئی انٹرنیٹ کنکشن نہیں"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi مربوط ہے"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS کی تلاش کر رہا ہے"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"مقام متعین کیا گیا بذریعہ GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"مقام کی درخواستیں فعال ہیں"</string>
@@ -407,9 +402,11 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"صارف کو ہٹائیں؟"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"اس صارف کی سبھی ایپس اور ڈیٹا حذف کر دیا جائے گا۔"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"ہٹائیں"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"بیٹری سیور آن ہے"</string>
+ <!-- no translation found for battery_saver_notification_title (8614079794522291840) -->
+ <skip />
<string name="battery_saver_notification_text" msgid="820318788126672692">"کارکردگی اور پس منظر کا ڈیٹا کم کر دیتا ہے"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"بیٹری کی بچت آف کریں"</string>
+ <!-- no translation found for battery_saver_notification_action_text (132118784269455533) -->
+ <skip />
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> آپ کی اسکرین پر ڈسپلے ہونے والی ہر چیز کو کیپچر کرنا شروع کر دیگی۔"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"دوبارہ نہ دکھائیں"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"سبھی کو صاف کریں"</string>
@@ -588,8 +585,8 @@
<item quantity="one">%d منٹ</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"بیٹری کا استعمال"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"چارجنگ کے دوران بیٹری سیور دستیاب نہیں ہے"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"بیٹری سیور"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"چارجنگ کے دوران بیٹری سیور دستیاب نہیں ہے"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"بیٹری سیور"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"کارکردگی اور پس منظر کا ڈیٹا کم کر دیتا ہے"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"بٹن <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-uz/config.xml b/packages/SystemUI/res/values-uz/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-uz/config.xml
+++ b/packages/SystemUI/res/values-uz/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 8722fb1..e66477f 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Eslatmalar"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Batareya quvvati kam qoldi"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> qoldi"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> qoldi. Quvvat tejash funksiyasi yoqilgan."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> qoldi. Quvvat tejash rejimi yoniq."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB orqali zaryadlab bo‘lmaydi.\nFaqat taklif qilingan zaryadlagichdan foydalaning."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB orqali quvvat oldirish qo‘llab-quvvatlanmaydi."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Faqat qurilma bilan kelgan quvvatlash moslamasidan foydalaning."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Sozlamalar"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Quvvat tejash funksiyasi yoqilsinmi?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Quvvat tejash yoqilsinmi?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Yoqish"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Quvvat tejash funksiyasini yoqing"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Quvvat tejash funksiyasini yoqing"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Sozlamalar"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Ekranning avtomatik burilishi"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth bog‘landi"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Kiritish usullarini moslash"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Tashqi tugmatag"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasiga USB qurilmaga kirish uchun ruxsat berilsinmi?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasiga USB qurilmaga kirish uchun ruxsat berilsinmi?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"USB qurilma ulanganda <xliff:g id="ACTIVITY">%1$s</xliff:g> ochilsinmi?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"USB jihoz ulanganda <xliff:g id="ACTIVITY">%1$s</xliff:g> ochilsinmi?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasiga <xliff:g id="USB_DEVICE">%2$s</xliff:g> qurilmasidan foydalanishga ruxsat berilsinmi?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasiga <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> qurilmasidan foydalanishga ruxsat berilsinmi?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> bilan ishlash uchun <xliff:g id="APPLICATION">%1$s</xliff:g> ochilsinmi?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> bilan ishlash uchun <xliff:g id="APPLICATION">%1$s</xliff:g> ochilsinmi?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Bu USB jihoz bilan ishlash uchun dastur o‘rnatilmagan.Ushbu jihoz haqida: <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB jihoz"</string>
<string name="label_view" msgid="6304565553218192990">"Ko‘rish"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Ushbu USB qurilmadan standart sifatida foydalanish"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Ushbu USB jihozdan standart sifatida foydalanish"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ulanganda, doim <xliff:g id="APPLICATION">%1$s</xliff:g> ochilsin"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ulanganda, doim <xliff:g id="APPLICATION">%1$s</xliff:g> ochilsin"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB orqali nosozliklarni tuzatishga ruxsat berilsinmi?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Kompyuterning RSA tugmasi barmoq izlari:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Doimo ushbu kompyuterdan ruxsat berilsin"</string>
@@ -245,8 +245,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Internetdan foydalanish to‘xtatib qo‘yildi"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Belgilangan trafik sarflab bo‘lindi. Endi mobil internetdan foydalana olmaysiz.\n\nDavom ettiradigan bo‘lsangiz, trafik uchun to‘lov olinishi mumkin."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Davom etish"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Internetga ulanmagan"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ulandi"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS qidirilmoqda"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS yordamida manzilni o‘rnatish"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Joylashuv so‘rovlari yoniq"</string>
@@ -403,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Foydalanuvchi olib tashlansinmi?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Ushbu foydalanuvchining barcha ilovalari va ma’lumotlari o‘chirib tashlanadi."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Olib tashlash"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Quvvat tejash rejimi yoqildi"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Quvvat tejash rejimi yoniq"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Unumdorlik pasayadi va fonda internetdan foydalanish cheklanadi"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Quvvat tejash rejimidan chiqish"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Quvvat tejash rejimidan chiqish"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ilovasi qurilma ekranidagi har qanday tasvirni ko‘rishni boshlaydi."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Boshqa ko‘rsatilmasin"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Hammasini tozalash"</string>
@@ -584,8 +582,8 @@
<item quantity="one">%d daqiqa</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Batareya sarfi"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Quvvat tejash rejimidan quvvatlash vaqtida foydalanib bo‘lmaydi"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Quvvat tejash rejimi"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Quvvat tejash rejimidan quvvatlash vaqtida foydalanib bo‘lmaydi"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Quvvat tejash rejimi"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Unumdorlik pasayadi va fonda internetdan foydalanish cheklanadi"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> tugmasi"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Bosh ekran"</string>
diff --git a/packages/SystemUI/res/values-vi/config.xml b/packages/SystemUI/res/values-vi/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-vi/config.xml
+++ b/packages/SystemUI/res/values-vi/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 36e76fe..237920d 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Thông báo"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Pin yếu"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Còn lại <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Còn lại <xliff:g id="PERCENTAGE">%s</xliff:g>. Trình tiết kiệm pin đang bật."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Còn lại <xliff:g id="PERCENTAGE">%s</xliff:g>. Trình tiết kiệm pin đang bật."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Không hỗ trợ sạc qua USB.\nChỉ sử dụng bộ sạc được cung cấp."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Sạc qua USB không được hỗ trợ."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Chỉ sử dụng bộ sạc được cung cấp."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Cài đặt"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Bật trình tiết kiệm pin?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Bật trình tiết kiệm pin?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Bật"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Bật trình tiết kiệm pin"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Bật trình tiết kiệm pin"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Cài đặt"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Tự động xoay màn hình"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth được dùng làm điểm truy cập Internet"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Thiết lập phương thức nhập"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Bàn phím thực"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Cho phép ứng dụng <xliff:g id="APPLICATION">%1$s</xliff:g> truy cập thiết bị USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Cho phép ứng dụng <xliff:g id="APPLICATION">%1$s</xliff:g> truy cập phụ kiện USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Mở <xliff:g id="ACTIVITY">%1$s</xliff:g> khi thiết bị USB này được kết nối?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Mở <xliff:g id="ACTIVITY">%1$s</xliff:g> khi phụ kiện USB này được kết nối?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Cho phép <xliff:g id="APPLICATION">%1$s</xliff:g> truy cập <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Cho phép <xliff:g id="APPLICATION">%1$s</xliff:g> truy cập <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Mở <xliff:g id="APPLICATION">%1$s</xliff:g> để điều khiển <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Mở <xliff:g id="APPLICATION">%1$s</xliff:g> để điều khiển <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Không có ứng dụng được cài đặt nào hoạt động với phụ kiện USB này. Tìm hiểu thêm về phụ kiện này tại <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Phụ kiện USB"</string>
<string name="label_view" msgid="6304565553218192990">"Xem"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Sử dụng theo mặc định cho thiết bị USB này"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Sử dụng theo mặc định cho phụ kiện USB này"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Luôn mở <xliff:g id="APPLICATION">%1$s</xliff:g> khi kết nối <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Luôn mở <xliff:g id="APPLICATION">%1$s</xliff:g> khi kết nối <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Cho phép gỡ lỗi USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Tệp tham chiếu khóa RSA của máy tính là:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Luôn cho phép từ máy tính này"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Đã tạm dừng dữ liệu"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Dữ liệu đã đạt đến mức giới hạn mà bạn đã đặt. Bạn hiện không sử dụng dữ liệu di động nữa.\n\nNếu tiếp tục, bạn có thể bị tính phí sử dụng dữ liệu."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Tiếp tục"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ko có k.nối Internet"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Đã kết nối Wi-Fi"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Đang tìm kiếm GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Vị trí đặt bởi GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Yêu cầu về thông tin vị trí đang hoạt động"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Xóa người dùng?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Tất cả các ứng dụng và dữ liệu của người dùng này sẽ bị xóa."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Xóa"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Trình tiết kiệm pin đang bật"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Trình tiết kiệm pin đang bật"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Giảm hiệu suất và dữ liệu nền"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Tắt trình tiết kiệm pin"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Tắt trình tiết kiệm pin"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sẽ bắt đầu chụp mọi thứ hiển thị trên màn hình."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Không hiển thị lại"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Xóa tất cả"</string>
@@ -584,8 +582,8 @@
<item quantity="one">%d phút</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Mức sử dụng pin"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Không sử dụng được trình tiết kiệm pin trong khi sạc"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Trình tiết kiệm pin"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Trình tiết kiệm pin không khả dụng trong khi sạc"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Trình tiết kiệm pin"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Giảm hiệu suất và dữ liệu nền"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Nút <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 74afc22..d80d1bf 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
<string name="battery_low_title" msgid="6456385927409742437">"电池电量偏低"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"剩余<xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"剩余<xliff:g id="PERCENTAGE">%s</xliff:g>。省电模式已开启。"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"剩余 <xliff:g id="PERCENTAGE">%s</xliff:g>。省电模式已开启。"</string>
<string name="invalid_charger" msgid="4549105996740522523">"不支持USB充电功能。\n只能使用随附的充电器充电。"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"不支持USB充电。"</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"仅限使用设备随附的充电器。"</string>
<string name="battery_low_why" msgid="4553600287639198111">"设置"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"要开启省电模式吗?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"要开启省电模式吗?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"开启"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"开启省电模式"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"开启省电模式"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"设置"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WLAN"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"自动旋转屏幕"</string>
@@ -51,21 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"已通过蓝牙共享网络"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"设置输入法"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"物理键盘"</string>
- <!-- no translation found for usb_device_permission_prompt (1825685909587559679) -->
- <skip />
- <!-- no translation found for usb_accessory_permission_prompt (2465531696941369047) -->
- <skip />
- <!-- no translation found for usb_device_confirm_prompt (7440562274256843905) -->
- <skip />
- <!-- no translation found for usb_accessory_confirm_prompt (4333670517539993561) -->
- <skip />
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"要允许<xliff:g id="APPLICATION">%1$s</xliff:g>访问<xliff:g id="USB_DEVICE">%2$s</xliff:g>吗?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"要允许<xliff:g id="APPLICATION">%1$s</xliff:g>访问<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>吗?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"要打开<xliff:g id="APPLICATION">%1$s</xliff:g>来处理<xliff:g id="USB_DEVICE">%2$s</xliff:g>吗?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"要打开<xliff:g id="APPLICATION">%1$s</xliff:g>来处理<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>吗?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"未安装此USB配件适用的应用。要了解此配件的详情,请访问:<xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB配件"</string>
<string name="label_view" msgid="6304565553218192990">"查看"</string>
- <!-- no translation found for always_use_device (4015357883336738417) -->
- <skip />
- <!-- no translation found for always_use_accessory (3257892669444535154) -->
- <skip />
+ <string name="always_use_device" msgid="4015357883336738417">"连接<xliff:g id="USB_DEVICE">%2$s</xliff:g>后一律打开<xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"连接<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>后一律打开<xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"允许 USB 调试吗?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"这台计算机的 RSA 密钥指纹如下:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"一律允许使用这台计算机进行调试"</string>
@@ -249,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"数据网络已暂停使用"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"您的数据流量消耗已达到所设置的上限,因此已停用移动数据网络。\n\n如果您要继续使用移动数据网络,则可能需要支付相应的流量费用。"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢复"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"未连接互联网"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"已连接到WLAN网络"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"正在搜索GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"已通过GPS确定位置"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"应用发出了有效位置信息请求"</string>
@@ -407,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"是否移除用户?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"此用户的所有应用和数据均将被删除。"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"移除"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"省电模式已开启"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"省电模式已开启"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"降低性能并限制后台流量"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"关闭省电模式"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"关闭省电模式"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>将开始截取您的屏幕上显示的所有内容。"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"不再显示"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"全部清除"</string>
@@ -588,8 +580,8 @@
<item quantity="one">%d 分钟</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"电池使用情况"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"充电过程中无法使用省电模式"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"省电模式"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"充电过程中无法使用省电模式"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"省电模式"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"降低性能并限制后台流量"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g>按钮"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/config.xml b/packages/SystemUI/res/values-zh-rHK/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-zh-rHK/config.xml
+++ b/packages/SystemUI/res/values-zh-rHK/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index b34ff37..7da008d 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
<string name="battery_low_title" msgid="6456385927409742437">"電量低"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"剩餘 <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"剩餘 <xliff:g id="PERCENTAGE">%s</xliff:g>。開啟省電模式。"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"剩餘 <xliff:g id="PERCENTAGE">%s</xliff:g>。省電模式已開啟。"</string>
<string name="invalid_charger" msgid="4549105996740522523">"不支援 USB 充電。\n僅能使用隨附的充電器。"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"不支援 USB 充電功能。"</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"僅限使用裝置隨附的充電器。"</string>
<string name="battery_low_why" msgid="4553600287639198111">"設定"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"要開啟省電模式嗎?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"要開啟省電模式嗎?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"開啟"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"開啟省電模式"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"開啟省電模式"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"設定"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"自動旋轉螢幕"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"已經由藍牙進行網絡共享"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"設定輸入法"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"實體鍵盤"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"允許「<xliff:g id="APPLICATION">%1$s</xliff:g>」應用程式存取 USB 裝置嗎?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"允許「<xliff:g id="APPLICATION">%1$s</xliff:g>」應用程式存取 USB 配件嗎?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"連接這個 USB 裝置時啟用 <xliff:g id="ACTIVITY">%1$s</xliff:g> 嗎?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"連接這個 USB 配件時啟用 <xliff:g id="ACTIVITY">%1$s</xliff:g> 嗎?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"要允許「<xliff:g id="APPLICATION">%1$s</xliff:g>」存取「<xliff:g id="USB_DEVICE">%2$s</xliff:g>」嗎?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"要允許「<xliff:g id="APPLICATION">%1$s</xliff:g>」存取「<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>」嗎?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"要開啟「<xliff:g id="APPLICATION">%1$s</xliff:g>」處理「<xliff:g id="USB_DEVICE">%2$s</xliff:g>」嗎?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"要開啟「<xliff:g id="APPLICATION">%1$s</xliff:g>」處理「<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>」嗎?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"已安裝的應用程式均無法存取這個 USB 配件,如要進一步瞭解這個配件,請瀏覽 <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB 配件"</string>
<string name="label_view" msgid="6304565553218192990">"觀看"</string>
- <string name="always_use_device" msgid="1450287437017315906">"預設用於這個 USB 裝置"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"預設用於這個 USB 配件"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"連接「<xliff:g id="USB_DEVICE">%2$s</xliff:g>」時一律開啟「<xliff:g id="APPLICATION">%1$s</xliff:g>」"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"連接「<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>」時一律開啟「<xliff:g id="APPLICATION">%1$s</xliff:g>」"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"允許 USB 除錯嗎?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"這部電腦的 RSA 密鑰指紋如下:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"一律允許透過這部電腦進行"</string>
@@ -245,8 +245,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"已暫停使用數據"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"您的數據用量已達到所設定的上限,因此系統已停用流動數據連線。\n\n如果您恢復使用流動數據連線,可能需要支付數據用量費用。"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢復"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"沒有互聯網連線"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 已連線"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"正在搜尋 GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS 已定位"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"位置要求啟動中"</string>
@@ -403,9 +401,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"移除使用者?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"系統將會刪除這個使用者的所有應用程式和資料。"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"移除"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"省電模式已開啟"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"省電模式已開啟"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"降低效能並限制背景數據傳輸"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"關閉省電模式"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"關閉省電模式"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 將開始擷取您的螢幕上顯示的內容。"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"不用再顯示"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"全部清除"</string>
@@ -584,8 +582,8 @@
<item quantity="one">%d 分鐘</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"電池用量"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"充電時無法使用省電模式"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"省電模式"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"充電時無法使用「省電模式」"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"省電模式"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"降低效能並限制背景數據傳輸"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> 鍵"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/config.xml b/packages/SystemUI/res/values-zh-rTW/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-zh-rTW/config.xml
+++ b/packages/SystemUI/res/values-zh-rTW/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 13ac5e7..efb48cd 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
<string name="battery_low_title" msgid="6456385927409742437">"電池電力不足"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"僅剩 <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"僅剩 <xliff:g id="PERCENTAGE">%s</xliff:g>。節約耗電量模式已開啟。"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"僅剩 <xliff:g id="PERCENTAGE">%s</xliff:g>。節約耗電量模式已開啟。"</string>
<string name="invalid_charger" msgid="4549105996740522523">"不支援 USB 充電。\n僅能使用隨附的充電器。"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"不支援 USB 充電功能。"</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"僅限使用裝置隨附的充電器。"</string>
<string name="battery_low_why" msgid="4553600287639198111">"設定"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"要開啟節約耗電量模式嗎?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"要開啟節約耗電量模式嗎?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"開啟"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"開啟節約耗電量模式"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"開啟節約耗電量模式"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"設定"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"自動旋轉螢幕"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"藍牙網路共用已開"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"設定輸入法"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"實體鍵盤"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"允許 <xliff:g id="APPLICATION">%1$s</xliff:g> 應用程式存取 USB 裝置嗎?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"允許 <xliff:g id="APPLICATION">%1$s</xliff:g> 應用程式存取 USB 配件嗎?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"連接這個 USB 裝置時啟用 <xliff:g id="ACTIVITY">%1$s</xliff:g> 嗎?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"連接這個 USB 配件時啟用 <xliff:g id="ACTIVITY">%1$s</xliff:g> 嗎?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"要允許「<xliff:g id="APPLICATION">%1$s</xliff:g>」存取「<xliff:g id="USB_DEVICE">%2$s</xliff:g>」嗎?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"要允許「<xliff:g id="APPLICATION">%1$s</xliff:g>」存取「<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>」嗎?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"要開啟「<xliff:g id="APPLICATION">%1$s</xliff:g>」處理「<xliff:g id="USB_DEVICE">%2$s</xliff:g>」嗎?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"要開啟「<xliff:g id="APPLICATION">%1$s</xliff:g>」處理「<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>」嗎?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"已安裝的應用程式均無法存取這個 USB 配件,如要進一步瞭解這個配件,請造訪 <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB 配件"</string>
<string name="label_view" msgid="6304565553218192990">"查看"</string>
- <string name="always_use_device" msgid="1450287437017315906">"預設用於這個 USB 裝置"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"預設用於這個 USB 配件"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"當「<xliff:g id="USB_DEVICE">%2$s</xliff:g>」連接時一律開啟「<xliff:g id="APPLICATION">%1$s</xliff:g>」"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"當「<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>」連接時一律開啟「<xliff:g id="APPLICATION">%1$s</xliff:g>」"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"允許 USB 偵錯嗎?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"這台電腦的 RSA 金鑰指紋如下:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"一律允許透過這台電腦進行"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"已暫停數據連線"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"你的數據用量已達設定的用量上限,因此系統已停止使用行動數據連線。\n\n如果你繼續使用行動數據連線,可能需要支付相關的數據傳輸費用。"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢復連線"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"沒有網際網路連線"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 已連線"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"正在搜尋 GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS 已定位"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"有位置資訊要求"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"要移除使用者嗎?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"系統將刪除這個使用者的所有應用程式和資料。"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"移除"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"節約耗電量模式已啟用"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"節約耗電量模式已開啟"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"降低效能並限制背景數據傳輸"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"關閉節約耗電量模式"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"關閉節約耗電量模式"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 將開始擷取你的螢幕上顯示的內容。"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"不要再顯示"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"全部清除"</string>
@@ -582,8 +580,8 @@
<item quantity="one">%d 分鐘</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"電池用量"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"充電時無法使用節約耗電量模式"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"節約耗電量"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"充電時無法使用節約耗電量模式"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"節約耗電量"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"降低效能並限制背景資料傳輸"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> 按鈕"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home 鍵"</string>
diff --git a/packages/SystemUI/res/values-zu/config.xml b/packages/SystemUI/res/values-zu/config.xml
index 5309563..477f219 100644
--- a/packages/SystemUI/res/values-zu/config.xml
+++ b/packages/SystemUI/res/values-zu/config.xml
@@ -22,5 +22,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 695adf8..5094de9 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Izaziso"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Ibhethri liphansi"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> okusele"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> okusele. Isilondolozi sebhethri sivulekile."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> esele. Isilondolozi sebhethri sivuliwe."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Ukushaja i-USB akusekelwe.\nSebenzisa kuphela ishaja enikeziwe."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Ukushaja kwe-USB akusekelwe."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Sebenzisa kuphela ishaja enikeziwe."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Izilungiselelo"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Vula isilondolozi sebhethri?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Vula isilondolozi sebhethri?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Vula"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"Vula isilondolozi sebhethri"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"Vula isilondolozi sebhethri"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Izilungiselelo"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"I-Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Ukuzulazula kweskrini okuzenzakalelayo"</string>
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Ukusebenzisa i-Bluetooth njengemodemu"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Izilungiselelo zezindlela zokufakwayo"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Ukwakheka kwekhibhodi"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Vumela uhlelo lokusebenza <xliff:g id="APPLICATION">%1$s</xliff:g> ukuthi ufinyelele ezintweni eziphuma ne-USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vumela uhlelo lokusebenza <xliff:g id="APPLICATION">%1$s</xliff:g> ukuthi ufinyelele ezintweni eziphuma ne-USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vula <xliff:g id="ACTIVITY">%1$s</xliff:g> uma ledivayisi ye-USB ixhunyiwe?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Vula <xliff:g id="ACTIVITY">%1$s</xliff:g> uma le-accessory ye-USB ixhunyiwe"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Vumela i-<xliff:g id="APPLICATION">%1$s</xliff:g> ukufinyelela i-<xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Vumela i-<xliff:g id="APPLICATION">%1$s</xliff:g> ukufinyelela i-<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Vula i-<xliff:g id="APPLICATION">%1$s</xliff:g> ukuze uphath i-<xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Vula i-<xliff:g id="APPLICATION">%1$s</xliff:g> ukuze uphath i-<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Azikho izinhlelo zokusebenza ezisebenze ngezinto ze-USB. Funda okwengeziwe ngale into kwi <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"ama-accessory e-USB"</string>
<string name="label_view" msgid="6304565553218192990">"Buka"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Sebenzisa ngokuzenzakalelayo yale divayisi ye-USB"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Sebenzisa ngokuzenzakalelayo kule-accessory ye-USB"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Njalo vula i-<xliff:g id="APPLICATION">%1$s</xliff:g> uma i-<xliff:g id="USB_DEVICE">%2$s</xliff:g> ixhumekile"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Njalo vula i-<xliff:g id="APPLICATION">%1$s</xliff:g> uma i-<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ixhumekile"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Vumela ukulungisa iphutha le-USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Izigxivizo zeminwe zokhiye we-RSA wekhompyutha ngu:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Hlala uvumela njalo kusuka kule khompyutha"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Idatha imisiwe"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Umkhawulo wedatha owusethayo ufinyelelwe. Awusasebenzisi idatha yeselula.\n\nUma uqhubeka futhi, izindleko zingasebenza ekusetshenzisweni kwedatha."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Qalisa kabusha"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Alukho uxhumano lwe-Inthanethi"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"I-Wi-Fi ixhunyiwe"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Isesha i-GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Indawo ihlelwe i-GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Izicelo zendawo ziyasebenza"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Susa umsebenzisi?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Zonke izinhlelo zokusebenza nedatha yalo msebenzisi kuzosuswa."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Susa"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Isilondolozi sebhethri sivuliwe"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"Isilondolozi sebhethri sivuliwe"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Sehlisa ukusebenza nedatha yasemuva"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Vala isilondolozi sebhethri"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Vala isilondolozi sebhethri"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> izoqala ukuthwebula yonke into eboniswa kusikrini sakho."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ungabonisi futhi"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Sula konke"</string>
@@ -582,8 +580,8 @@
<item quantity="other">%d amaminithi</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Ukusetshenziswa kwebhethri"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"Isilondolozi sebhethri asitholakali ngesikhathi sokushaja"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"Isilondolozi sebhethri"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Isilondolozi sebhethri asitholakali ngesikhathi sokushaja"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"Isilondolozi sebhethri"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Sehlisa ukusebenza nedatha yasemuva"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Inkinobho <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Ekhaya"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index cf79238..5e7f9c6 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -250,10 +250,7 @@
<string name="doze_brightness_sensor_type" translatable="false"></string>
<!-- Doze: pulse parameter - how long does it take to fade in? -->
- <integer name="doze_pulse_duration_in">900</integer>
-
- <!-- Doze: pulse parameter - how long does it take to fade in after a pickup? -->
- <integer name="doze_pulse_duration_in_pickup">130</integer>
+ <integer name="doze_pulse_duration_in">130</integer>
<!-- Doze: pulse parameter - once faded in, how long does it stay visible? -->
<integer name="doze_pulse_duration_visible">6000</integer>
@@ -319,6 +316,40 @@
<!-- SystemUIFactory component -->
<string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.SystemUIFactory</string>
+ <!-- SystemUI Services: The classes of the stuff to start. -->
+ <string-array name="config_systemUIServiceComponents" translatable="false">
+ <item>com.android.systemui.Dependency</item>
+ <item>com.android.systemui.util.NotificationChannels</item>
+ <item>com.android.systemui.statusbar.CommandQueue$CommandQueueStart</item>
+ <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
+ <item>com.android.systemui.recents.Recents</item>
+ <item>com.android.systemui.volume.VolumeUI</item>
+ <item>com.android.systemui.stackdivider.Divider</item>
+ <item>com.android.systemui.SystemBars</item>
+ <item>com.android.systemui.usb.StorageNotification</item>
+ <item>com.android.systemui.power.PowerUI</item>
+ <item>com.android.systemui.media.RingtonePlayer</item>
+ <item>com.android.systemui.keyboard.KeyboardUI</item>
+ <item>com.android.systemui.pip.PipUI</item>
+ <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
+ <item>@string/config_systemUIVendorServiceComponent</item>
+ <item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
+ <item>com.android.systemui.LatencyTester</item>
+ <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
+ <item>com.android.systemui.RoundedCorners</item>
+ <item>com.android.systemui.EmulatedDisplayCutout</item>
+ </string-array>
+
+ <!-- SystemUI vender service, used in config_systemUIServiceComponents. -->
+ <string name="config_systemUIVendorServiceComponent" translatable="false">com.android.systemui.VendorServices</string>
+
+ <!-- SystemUI Services (per user): The classes of the stuff to start for each user. This is a subset of the config_systemUIServiceComponents -->
+ <string-array name="config_systemUIServiceComponentsPerUser" translatable="false">
+ <item>com.android.systemui.Dependency</item>
+ <item>com.android.systemui.util.NotificationChannels</item>
+ <item>com.android.systemui.recents.Recents</item>
+ </string-array>
+
<!-- Nav bar button default ordering/layout -->
<string name="config_navBarLayout" translatable="false">left[.5W],back[1WC];home;recent[1WC],right[.5W]</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f0bad2a..0715d49 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -72,16 +72,19 @@
<dimen name="status_bar_connected_device_bt_indicator_size">17dp</dimen>
<!-- Height of a small notification in the status bar-->
- <dimen name="notification_min_height">92dp</dimen>
+ <dimen name="notification_min_height">100dp</dimen>
<!-- Increased height of a small notification in the status bar -->
- <dimen name="notification_min_height_increased">132dp</dimen>
+ <dimen name="notification_min_height_increased">140dp</dimen>
<!-- Height of a small notification in the status bar which was used before android N -->
<dimen name="notification_min_height_legacy">64dp</dimen>
+ <!-- Height of a small notification in the status bar which was used before android P -->
+ <dimen name="notification_min_height_before_p">92dp</dimen>
+
<!-- Height of a large notification in the status bar -->
- <dimen name="notification_max_height">284dp</dimen>
+ <dimen name="notification_max_height">292dp</dimen>
<!-- Height of an ambient notification on ambient display -->
<dimen name="notification_ambient_height">400dp</dimen>
@@ -89,12 +92,21 @@
<!-- Height of a heads up notification in the status bar for legacy custom views -->
<dimen name="notification_max_heads_up_height_legacy">128dp</dimen>
+ <!-- Height of a heads up notification in the status bar for custom views before andoid P -->
+ <dimen name="notification_max_heads_up_height_before_p">148dp</dimen>
+
<!-- Height of a heads up notification in the status bar -->
- <dimen name="notification_max_heads_up_height">148dp</dimen>
+ <dimen name="notification_max_heads_up_height">156dp</dimen>
<!-- Height of a heads up notification in the status bar -->
<dimen name="notification_max_heads_up_height_increased">188dp</dimen>
+ <!-- Side padding on the lockscreen on the side of notifications -->
+ <dimen name="notification_lockscreen_side_paddings">8dp</dimen>
+
+ <!-- Additional side padding for custom content if the app doesn't target P yet -->
+ <dimen name="notification_content_custom_view_side_padding">@dimen/notification_lockscreen_side_paddings</dimen>
+
<!-- Height of a messaging notifications with actions at least. Not that this is an upper bound
and the notification won't use this much, but is measured with wrap_content -->
<dimen name="notification_messaging_actions_min_height">196dp</dimen>
@@ -109,7 +121,7 @@
<dimen name="notification_min_interaction_height">40dp</dimen>
<!-- the padding of the shelf icon container -->
- <dimen name="shelf_icon_container_padding">13dp</dimen>
+ <dimen name="shelf_icon_container_padding">21dp</dimen>
<!-- The padding of a notification icon on top to the start of the notification. Used for custom
views where the distance can't be measured -->
@@ -213,6 +225,9 @@
etc. -->
<dimen name="qs_footer_height">48dp</dimen>
+ <!-- The padding between the notifications and the quick settings container -->
+ <dimen name="qs_notification_keyguard_padding">8dp</dimen>
+
<!-- Height of the status bar header bar when expanded -->
<dimen name="status_bar_header_height_expanded">124dp</dimen>
@@ -348,10 +363,6 @@
<!-- Default distance from each snap target that GlowPadView considers a "hit" -->
<dimen name="glowpadview_inner_radius">15dip</dimen>
- <!-- bottom_stack_peek_amount + notification_min_height
- + notification_collapse_second_card_padding -->
- <dimen name="min_stack_height">104dp</dimen>
-
<!-- Z distance between notifications if they are in the stack -->
<dimen name="z_distance_between_notifications">0.5dp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index cfd95b4..dd31365 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -47,6 +47,7 @@
<item type="id" name="qs_icon_tag"/>
<item type="id" name="qs_slash_tag"/>
<item type="id" name="scrim"/>
+ <item type="id" name="scrim_blanking"/>
<item type="id" name="scrim_target"/>
<item type="id" name="scrim_alpha_start"/>
<item type="id" name="scrim_alpha_end"/>
@@ -77,6 +78,18 @@
<item type="id" name="action_move_tl_30" />
<item type="id" name="action_move_rb_full" />
+ <item type="id" name="bottom_roundess_animator_tag"/>
+ <item type="id" name="bottom_roundess_animator_start_tag"/>
+ <item type="id" name="bottom_roundess_animator_end_tag"/>
+
+ <item type="id" name="top_roundess_animator_tag"/>
+ <item type="id" name="top_roundess_animator_start_tag"/>
+ <item type="id" name="top_roundess_animator_end_tag"/>
+
+ <item type="id" name="side_padding_animator_tag"/>
+ <item type="id" name="side_padding_animator_start_tag"/>
+ <item type="id" name="side_padding_animator_end_tag"/>
+
<!-- Accessibility actions for the notification menu -->
<item type="id" name="action_snooze_undo"/>
<item type="id" name="action_snooze_shorter"/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ca85445..62ab74d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1248,6 +1248,10 @@
<string name="stream_tts" translatable="false">Transmitted Through Speaker</string> <!-- STREAM_TTS -->
<string name="stream_accessibility">Accessibility</string> <!-- STREAM_ACCESSIBILITY -->
+ <string name="volume_ringer_status_normal">Ring</string>
+ <string name="volume_ringer_status_vibrate">Vibrate</string>
+ <string name="volume_ringer_status_silent">Mute</string>
+
<string name="volume_stream_muted" translatable="false">%s silent</string>
<string name="volume_stream_vibrate" translatable="false">%s vibrate</string>
<string name="volume_stream_suppressed" translatable="false">%1$s silent — %2$s</string>
@@ -1989,8 +1993,8 @@
<!-- Action label for launching app info on the specified app [CHAR LIMIT=20] -->
<string name="app_info">App info</string>
- <!-- Action label for switching to web for an instant app [CHAR LIMIT=20] -->
- <string name="go_to_web">Go to web</string>
+ <!-- Action label for switching to a browser for an instant app [CHAR LIMIT=20] -->
+ <string name="go_to_web">Go to browser</string>
<!-- Quick settings tile for toggling mobile data [CHAR LIMIT=20] -->
<string name="mobile_data">Mobile data</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index 17cb0d8..7db3ac6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -43,6 +43,9 @@
public void onActivityDismissingDockedStack() { }
public void onActivityLaunchOnSecondaryDisplayFailed() { }
public void onTaskProfileLocked(int taskId, int userId) { }
+ public void onTaskRemoved(int taskId) { }
+ public void onTaskMovedToFront(int taskId) { }
+ public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) { }
/**
* Checks that the current user matches the process. Since
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index 81c37a9..857e0ea 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -145,6 +145,23 @@
mHandler.obtainMessage(H.ON_TASK_SNAPSHOT_CHANGED, taskId, 0, snapshot).sendToTarget();
}
+ @Override
+ public void onTaskRemoved(int taskId) throws RemoteException {
+ mHandler.obtainMessage(H.ON_TASK_REMOVED, taskId, 0).sendToTarget();
+ }
+
+ @Override
+ public void onTaskMovedToFront(int taskId) throws RemoteException {
+ mHandler.obtainMessage(H.ON_TASK_MOVED_TO_FRONT, taskId, 0).sendToTarget();
+ }
+
+ @Override
+ public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation)
+ throws RemoteException {
+ mHandler.obtainMessage(H.ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE, taskId,
+ requestedOrientation).sendToTarget();
+ }
+
private final class H extends Handler {
private static final int ON_TASK_STACK_CHANGED = 1;
private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
@@ -157,6 +174,10 @@
private static final int ON_PINNED_STACK_ANIMATION_STARTED = 9;
private static final int ON_ACTIVITY_UNPINNED = 10;
private static final int ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED = 11;
+ private static final int ON_TASK_REMOVED = 12;
+ private static final int ON_TASK_MOVED_TO_FRONT = 13;
+ private static final int ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE = 14;
+
public H(Looper looper) {
super(looper);
@@ -241,6 +262,25 @@
}
break;
}
+ case ON_TASK_REMOVED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskRemoved(msg.arg1);
+ }
+ break;
+ }
+ case ON_TASK_MOVED_TO_FRONT: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskMovedToFront(msg.arg1);
+ }
+ break;
+ }
+ case ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityRequestedOrientationChanged(
+ msg.arg1, msg.arg2);
+ }
+ break;
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index 775b9e8..a980413 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -16,8 +16,8 @@
package com.android.keyguard;
-import static com.android.keyguard.LatencyTracker.ACTION_CHECK_CREDENTIAL;
-import static com.android.keyguard.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
+import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL;
+import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
import android.content.Context;
import android.os.AsyncTask;
@@ -29,6 +29,7 @@
import android.view.View;
import android.widget.LinearLayout;
+import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternChecker;
import com.android.internal.widget.LockPatternUtils;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index ec5f356..d636316 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -15,8 +15,8 @@
*/
package com.android.keyguard;
-import static com.android.keyguard.LatencyTracker.ACTION_CHECK_CREDENTIAL;
-import static com.android.keyguard.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
+import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL;
+import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
import android.content.Context;
import android.graphics.Rect;
@@ -33,6 +33,7 @@
import android.view.animation.Interpolator;
import android.widget.LinearLayout;
+import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternChecker;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index 432b406..6e0b56e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -53,8 +53,13 @@
private ProgressDialog mSimUnlockProgressDialog = null;
private CheckSimPin mCheckSimPinThread;
+ // Below flag is set to true during power-up or when a new SIM card inserted on device.
+ // When this is true and when SIM card is PIN locked state, on PIN lock screen, message would
+ // be displayed to inform user about the number of remaining PIN attempts left.
+ private boolean mShowDefaultMessage = true;
+ private int mRemainingAttempts = -1;
private AlertDialog mRemainingAttemptsDialog;
- private int mSubId;
+ private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private ImageView mSimImageView;
KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
@@ -91,34 +96,71 @@
public void resetState() {
super.resetState();
if (DEBUG) Log.v(TAG, "Resetting state");
- KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
- mSubId = monitor.getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED);
- boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
- if (SubscriptionManager.isValidSubscriptionId(mSubId)) {
- int count = TelephonyManager.getDefault().getSimCount();
- Resources rez = getResources();
- String msg;
- int color = Color.WHITE;
- if (count < 2) {
- msg = rez.getString(R.string.kg_sim_pin_instructions);
- } else {
- SubscriptionInfo info = monitor.getSubscriptionInfoForSubId(mSubId);
- CharSequence displayName = info != null ? info.getDisplayName() : ""; // don't crash
- msg = rez.getString(R.string.kg_sim_pin_instructions_multi, displayName);
- if (info != null) {
- color = info.getIconTint();
- }
- }
- if (isEsimLocked) {
- msg = msg + " " + rez.getString(R.string.kg_sim_lock_instructions_esim);
- }
- mSecurityMessageDisplay.setMessage(msg);
- mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+ handleSubInfoChangeIfNeeded();
+ if (mShowDefaultMessage) {
+ showDefaultMessage();
}
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
+
KeyguardEsimArea esimButton = findViewById(R.id.keyguard_esim_area);
esimButton.setVisibility(isEsimLocked ? View.VISIBLE : View.GONE);
}
+ private void showDefaultMessage() {
+ if (mRemainingAttempts >= 0) {
+ mSecurityMessageDisplay.setMessage(getPinPasswordErrorMessage(
+ mRemainingAttempts, true));
+ return;
+ }
+
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
+ int count = TelephonyManager.getDefault().getSimCount();
+ Resources rez = getResources();
+ String msg;
+ int color = Color.WHITE;
+ if (count < 2) {
+ msg = rez.getString(R.string.kg_sim_pin_instructions);
+ } else {
+ SubscriptionInfo info = KeyguardUpdateMonitor.getInstance(mContext).
+ getSubscriptionInfoForSubId(mSubId);
+ CharSequence displayName = info != null ? info.getDisplayName() : ""; // don't crash
+ msg = rez.getString(R.string.kg_sim_pin_instructions_multi, displayName);
+ if (info != null) {
+ color = info.getIconTint();
+ }
+ }
+
+ if (isEsimLocked) {
+ msg = msg + " " + rez.getString(R.string.kg_sim_lock_instructions_esim);
+ }
+
+ mSecurityMessageDisplay.setMessage(msg);
+ mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+
+ // Sending empty PIN here to query the number of remaining PIN attempts
+ new CheckSimPin("", mSubId) {
+ void onSimCheckResponse(final int result, final int attemptsRemaining) {
+ Log.d(LOG_TAG, "onSimCheckResponse " + " dummy One result" + result +
+ " attemptsRemaining=" + attemptsRemaining);
+ if (attemptsRemaining >= 0) {
+ mRemainingAttempts = attemptsRemaining;
+ mSecurityMessageDisplay.setMessage(
+ getPinPasswordErrorMessage(attemptsRemaining, true));
+ }
+ }
+ }.start();
+ }
+
+ private void handleSubInfoChangeIfNeeded() {
+ KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
+ int subId = monitor.getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED);
+ if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) {
+ mSubId = subId;
+ mShowDefaultMessage = true;
+ mRemainingAttempts = -1;
+ }
+ }
+
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@@ -131,17 +173,19 @@
return 0;
}
- private String getPinPasswordErrorMessage(int attemptsRemaining) {
+ private String getPinPasswordErrorMessage(int attemptsRemaining, boolean isDefault) {
String displayMessage;
-
+ int msgId;
if (attemptsRemaining == 0) {
displayMessage = getContext().getString(R.string.kg_password_wrong_pin_code_pukked);
} else if (attemptsRemaining > 0) {
+ msgId = isDefault ? R.plurals.kg_password_default_pin_message :
+ R.plurals.kg_password_wrong_pin_code;
displayMessage = getContext().getResources()
- .getQuantityString(R.plurals.kg_password_wrong_pin_code, attemptsRemaining,
- attemptsRemaining);
+ .getQuantityString(msgId, attemptsRemaining, attemptsRemaining);
} else {
- displayMessage = getContext().getString(R.string.kg_password_pin_failed);
+ msgId = isDefault ? R.string.kg_sim_pin_instructions : R.string.kg_password_pin_failed;
+ displayMessage = getContext().getString(msgId);
}
if (DEBUG) Log.d(LOG_TAG, "getPinPasswordErrorMessage:"
+ " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage);
@@ -252,7 +296,7 @@
}
private Dialog getSimRemainingAttemptsDialog(int remaining) {
- String msg = getPinPasswordErrorMessage(remaining);
+ String msg = getPinPasswordErrorMessage(remaining, false);
if (mRemainingAttemptsDialog == null) {
Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage(msg);
@@ -288,6 +332,7 @@
post(new Runnable() {
@Override
public void run() {
+ mRemainingAttempts = attemptsRemaining;
if (mSimUnlockProgressDialog != null) {
mSimUnlockProgressDialog.hide();
}
@@ -296,8 +341,13 @@
if (result == PhoneConstants.PIN_RESULT_SUCCESS) {
KeyguardUpdateMonitor.getInstance(getContext())
.reportSimUnlocked(mSubId);
- mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ mRemainingAttempts = -1;
+ mShowDefaultMessage = true;
+ if (mCallback != null) {
+ mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ }
} else {
+ mShowDefaultMessage = false;
if (result == PhoneConstants.PIN_PASSWORD_INCORRECT) {
if (attemptsRemaining <= 2) {
// this is getting critical - show dialog
@@ -305,7 +355,7 @@
} else {
// show message
mSecurityMessageDisplay.setMessage(
- getPinPasswordErrorMessage(attemptsRemaining));
+ getPinPasswordErrorMessage(attemptsRemaining, false));
}
} else {
// "PIN operation failed!" - no idea what this was and no way to
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index 7f79008..876d170 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -52,11 +52,17 @@
private ProgressDialog mSimUnlockProgressDialog = null;
private CheckSimPuk mCheckSimPukThread;
+
+ // Below flag is set to true during power-up or when a new SIM card inserted on device.
+ // When this is true and when SIM card is PUK locked state, on PIN lock screen, message would
+ // be displayed to inform user about the number of remaining PUK attempts left.
+ private boolean mShowDefaultMessage = true;
+ private int mRemainingAttempts = -1;
private String mPukText;
private String mPinText;
private StateMachine mStateMachine = new StateMachine();
private AlertDialog mRemainingAttemptsDialog;
- private int mSubId;
+ private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private ImageView mSimImageView;
KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
@@ -132,34 +138,17 @@
}
}
+
void reset() {
mPinText="";
mPukText="";
state = ENTER_PUK;
- KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
- mSubId = monitor.getNextSubIdForState(IccCardConstants.State.PUK_REQUIRED);
- boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
- if (SubscriptionManager.isValidSubscriptionId(mSubId)) {
- int count = TelephonyManager.getDefault().getSimCount();
- Resources rez = getResources();
- String msg;
- int color = Color.WHITE;
- if (count < 2) {
- msg = rez.getString(R.string.kg_puk_enter_puk_hint);
- } else {
- SubscriptionInfo info = monitor.getSubscriptionInfoForSubId(mSubId);
- CharSequence displayName = info != null ? info.getDisplayName() : "";
- msg = rez.getString(R.string.kg_puk_enter_puk_hint_multi, displayName);
- if (info != null) {
- color = info.getIconTint();
- }
- }
- if (isEsimLocked) {
- msg = msg + " " + rez.getString(R.string.kg_sim_lock_instructions_esim);
- }
- mSecurityMessageDisplay.setMessage(msg);
- mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+ handleSubInfoChangeIfNeeded();
+ if (mShowDefaultMessage) {
+ showDefaultMessage();
}
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
+
KeyguardEsimArea esimButton = findViewById(R.id.keyguard_esim_area);
esimButton.setVisibility(isEsimLocked ? View.VISIBLE : View.GONE);
mPasswordEntry.requestFocus();
@@ -168,23 +157,79 @@
}
+ private void showDefaultMessage() {
+ if (mRemainingAttempts >= 0) {
+ mSecurityMessageDisplay.setMessage(getPukPasswordErrorMessage(
+ mRemainingAttempts, true));
+ return;
+ }
+
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
+ int count = TelephonyManager.getDefault().getSimCount();
+ Resources rez = getResources();
+ String msg;
+ int color = Color.WHITE;
+ if (count < 2) {
+ msg = rez.getString(R.string.kg_puk_enter_puk_hint);
+ } else {
+ SubscriptionInfo info = KeyguardUpdateMonitor.getInstance(mContext).
+ getSubscriptionInfoForSubId(mSubId);
+ CharSequence displayName = info != null ? info.getDisplayName() : "";
+ msg = rez.getString(R.string.kg_puk_enter_puk_hint_multi, displayName);
+ if (info != null) {
+ color = info.getIconTint();
+ }
+ }
+ if (isEsimLocked) {
+ msg = msg + " " + rez.getString(R.string.kg_sim_lock_instructions_esim);
+ }
+ mSecurityMessageDisplay.setMessage(msg);
+ mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+
+ // Sending empty PUK here to query the number of remaining PIN attempts
+ new CheckSimPuk("", "", mSubId) {
+ void onSimLockChangedResponse(final int result, final int attemptsRemaining) {
+ Log.d(LOG_TAG, "onSimCheckResponse " + " dummy One result" + result +
+ " attemptsRemaining=" + attemptsRemaining);
+ if (attemptsRemaining >= 0) {
+ mRemainingAttempts = attemptsRemaining;
+ mSecurityMessageDisplay.setMessage(
+ getPukPasswordErrorMessage(attemptsRemaining, true));
+ }
+ }
+ }.start();
+ }
+
+ private void handleSubInfoChangeIfNeeded() {
+ KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
+ int subId = monitor.getNextSubIdForState(IccCardConstants.State.PUK_REQUIRED);
+ if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) {
+ mSubId = subId;
+ mShowDefaultMessage = true;
+ mRemainingAttempts = -1;
+ }
+ }
+
@Override
protected int getPromtReasonStringRes(int reason) {
// No message on SIM Puk
return 0;
}
- private String getPukPasswordErrorMessage(int attemptsRemaining) {
+ private String getPukPasswordErrorMessage(int attemptsRemaining, boolean isDefault) {
String displayMessage;
if (attemptsRemaining == 0) {
displayMessage = getContext().getString(R.string.kg_password_wrong_puk_code_dead);
} else if (attemptsRemaining > 0) {
+ int msgId = isDefault ? R.plurals.kg_password_default_puk_message :
+ R.plurals.kg_password_wrong_puk_code;
displayMessage = getContext().getResources()
- .getQuantityString(R.plurals.kg_password_wrong_puk_code, attemptsRemaining,
- attemptsRemaining);
+ .getQuantityString(msgId, attemptsRemaining, attemptsRemaining);
} else {
- displayMessage = getContext().getString(R.string.kg_password_puk_failed);
+ int msgId = isDefault ? R.string.kg_puk_enter_puk_hint :
+ R.string.kg_password_puk_failed;
+ displayMessage = getContext().getString(msgId);
}
if (DEBUG) Log.d(LOG_TAG, "getPukPasswordErrorMessage:"
+ " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage);
@@ -303,7 +348,7 @@
}
private Dialog getPukRemainingAttemptsDialog(int remaining) {
- String msg = getPukPasswordErrorMessage(remaining);
+ String msg = getPukPasswordErrorMessage(remaining, false);
if (mRemainingAttemptsDialog == null) {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage(msg);
@@ -359,16 +404,25 @@
if (result == PhoneConstants.PIN_RESULT_SUCCESS) {
KeyguardUpdateMonitor.getInstance(getContext())
.reportSimUnlocked(mSubId);
- mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ mRemainingAttempts = -1;
+ mShowDefaultMessage = true;
+ if (mCallback != null) {
+ mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ }
} else {
+ mShowDefaultMessage = false;
if (result == PhoneConstants.PIN_PASSWORD_INCORRECT) {
+ // show message
+ mSecurityMessageDisplay.setMessage(getPukPasswordErrorMessage(
+ attemptsRemaining, false));
if (attemptsRemaining <= 2) {
// this is getting critical - show dialog
getPukRemainingAttemptsDialog(attemptsRemaining).show();
} else {
// show message
mSecurityMessageDisplay.setMessage(
- getPukPasswordErrorMessage(attemptsRemaining));
+ getPukPasswordErrorMessage(
+ attemptsRemaining, false));
}
} else {
mSecurityMessageDisplay.setMessage(getContext().getString(
diff --git a/packages/SystemUI/src/com/android/systemui/EmulatedDisplayCutout.java b/packages/SystemUI/src/com/android/systemui/EmulatedDisplayCutout.java
new file mode 100644
index 0000000..edd1748
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/EmulatedDisplayCutout.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.view.DisplayCutout;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+
+import java.util.ArrayList;
+
+/**
+ * Emulates a display cutout by drawing its shape in an overlay as supplied by
+ * {@link DisplayCutout}.
+ */
+public class EmulatedDisplayCutout extends SystemUI {
+ private View mOverlay;
+ private boolean mAttached;
+ private WindowManager mWindowManager;
+
+ @Override
+ public void start() {
+ mWindowManager = mContext.getSystemService(WindowManager.class);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.EMULATE_DISPLAY_CUTOUT),
+ false, mObserver, UserHandle.USER_ALL);
+ mObserver.onChange(false);
+ }
+
+ private void setAttached(boolean attached) {
+ if (attached && !mAttached) {
+ if (mOverlay == null) {
+ mOverlay = new CutoutView(mContext);
+ mOverlay.setLayoutParams(getLayoutParams());
+ }
+ mWindowManager.addView(mOverlay, mOverlay.getLayoutParams());
+ mAttached = true;
+ } else if (!attached && mAttached) {
+ mWindowManager.removeView(mOverlay);
+ mAttached = false;
+ }
+ }
+
+ private WindowManager.LayoutParams getLayoutParams() {
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+ | WindowManager.LayoutParams.FLAG_SLIPPERY
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR,
+ PixelFormat.TRANSLUCENT);
+ lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS
+ | WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
+ lp.setTitle("EmulatedDisplayCutout");
+ lp.gravity = Gravity.TOP;
+ return lp;
+ }
+
+ private ContentObserver mObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
+ @Override
+ public void onChange(boolean selfChange) {
+ boolean emulateCutout = Settings.Global.getInt(
+ mContext.getContentResolver(), Settings.Global.EMULATE_DISPLAY_CUTOUT,
+ Settings.Global.EMULATE_DISPLAY_CUTOUT_OFF)
+ != Settings.Global.EMULATE_DISPLAY_CUTOUT_OFF;
+ setAttached(emulateCutout);
+ }
+ };
+
+ private static class CutoutView extends View {
+ private Paint mPaint = new Paint();
+ private Path mPath = new Path();
+ private ArrayList<Point> mBoundingPolygon = new ArrayList<>();
+
+ CutoutView(Context context) {
+ super(context);
+ }
+
+ @Override
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ insets.getDisplayCutout().getBoundingPolygon(mBoundingPolygon);
+ invalidate();
+ return insets.consumeCutout();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (!mBoundingPolygon.isEmpty()) {
+ mPaint.setColor(Color.DKGRAY);
+ mPaint.setStyle(Paint.Style.FILL);
+
+ mPath.reset();
+ for (int i = 0; i < mBoundingPolygon.size(); i++) {
+ Point point = mBoundingPolygon.get(i);
+ if (i == 0) {
+ mPath.moveTo(point.x, point.y);
+ } else {
+ mPath.lineTo(point.x, point.y);
+ }
+ }
+ mPath.close();
+ canvas.drawPath(mPath, mPaint);
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
index d4149ea..9c847be 100644
--- a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
+++ b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
@@ -61,8 +61,3 @@
## 4: SYSTEM_REGISTER_USER System sysui registers user's callbacks
## 5: SYSTEM_UNREGISTER_USER System sysui unregisters user's callbacks (after death)
36060 sysui_recents_connection (type|1),(user|1)
-
-# ---------------------------
-# LatencyTracker.java
-# ---------------------------
-36070 sysui_latency (action|1|5),(latency|1|3)
diff --git a/packages/SystemUI/src/com/android/systemui/LatencyTester.java b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
index 1d55ee5..cbb69ee 100644
--- a/packages/SystemUI/src/com/android/systemui/LatencyTester.java
+++ b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
@@ -25,7 +25,7 @@
import android.os.SystemClock;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.LatencyTracker;
+import com.android.internal.util.LatencyTracker;
import com.android.systemui.statusbar.phone.FingerprintUnlockController;
import com.android.systemui.statusbar.phone.StatusBar;
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 9adafda..3538327 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -37,9 +37,7 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.media.RingtonePlayer;
import com.android.systemui.pip.PipUI;
-import com.android.systemui.plugins.GlobalActions;
import com.android.systemui.plugins.OverlayPlugin;
-import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.power.PowerUI;
@@ -54,6 +52,7 @@
import com.android.systemui.util.leak.GarbageMonitor;
import com.android.systemui.volume.VolumeUI;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@@ -66,44 +65,9 @@
private static final boolean DEBUG = false;
/**
- * The classes of the stuff to start.
- */
- private final Class<?>[] SERVICES = new Class[] {
- Dependency.class,
- NotificationChannels.class,
- CommandQueue.CommandQueueStart.class,
- KeyguardViewMediator.class,
- Recents.class,
- VolumeUI.class,
- Divider.class,
- SystemBars.class,
- StorageNotification.class,
- PowerUI.class,
- RingtonePlayer.class,
- KeyboardUI.class,
- PipUI.class,
- ShortcutKeyDispatcher.class,
- VendorServices.class,
- GarbageMonitor.Service.class,
- LatencyTester.class,
- GlobalActionsComponent.class,
- RoundedCorners.class,
- };
-
- /**
- * The classes of the stuff to start for each user. This is a subset of the services listed
- * above.
- */
- private final Class<?>[] SERVICES_PER_USER = new Class[] {
- Dependency.class,
- NotificationChannels.class,
- Recents.class
- };
-
- /**
* Hold a reference on the stuff we start.
*/
- private final SystemUI[] mServices = new SystemUI[SERVICES.length];
+ private SystemUI[] mServices;
private boolean mServicesStarted;
private boolean mBootCompleted;
private final Map<Class<?>, Object> mComponents = new HashMap<>();
@@ -149,7 +113,7 @@
// been broadcasted on startup for the primary SystemUI process. Instead, for
// components which require the SystemUI component to be initialized per-user, we
// start those components now for the current non-system user.
- startServicesIfNeeded(SERVICES_PER_USER);
+ startSecondaryUserServicesIfNeeded();
}
}
@@ -161,7 +125,8 @@
*/
public void startServicesIfNeeded() {
- startServicesIfNeeded(SERVICES);
+ String[] names = getResources().getStringArray(R.array.config_systemUIServiceComponents);
+ startServicesIfNeeded(names);
}
/**
@@ -171,13 +136,16 @@
* <p>This method must only be called from the main thread.</p>
*/
void startSecondaryUserServicesIfNeeded() {
- startServicesIfNeeded(SERVICES_PER_USER);
+ String[] names =
+ getResources().getStringArray(R.array.config_systemUIServiceComponentsPerUser);
+ startServicesIfNeeded(names);
}
- private void startServicesIfNeeded(Class<?>[] services) {
+ private void startServicesIfNeeded(String[] services) {
if (mServicesStarted) {
return;
}
+ mServices = new SystemUI[services.length];
if (!mBootCompleted) {
// check to see if maybe it was already completed long before we began
@@ -195,14 +163,16 @@
log.traceBegin("StartServices");
final int N = services.length;
for (int i = 0; i < N; i++) {
- Class<?> cl = services[i];
- if (DEBUG) Log.d(TAG, "loading: " + cl);
- log.traceBegin("StartServices" + cl.getSimpleName());
+ String clsName = services[i];
+ if (DEBUG) Log.d(TAG, "loading: " + clsName);
+ log.traceBegin("StartServices" + clsName);
long ti = System.currentTimeMillis();
+ Class cls;
try {
-
- Object newService = SystemUIFactory.getInstance().createInstance(cl);
- mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService);
+ cls = Class.forName(clsName);
+ mServices[i] = (SystemUI) cls.newInstance();
+ } catch(ClassNotFoundException ex){
+ throw new RuntimeException(ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InstantiationException ex) {
@@ -218,7 +188,7 @@
// Warn if initialization of component takes too long
ti = System.currentTimeMillis() - ti;
if (ti > 1000) {
- Log.w(TAG, "Initialization of " + cl.getName() + " took " + ti + " ms");
+ Log.w(TAG, "Initialization of " + cls.getName() + " took " + ti + " ms");
}
if (mBootCompleted) {
mServices[i].onBootCompleted();
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 0c067ff..45b11aa 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -27,7 +27,10 @@
import com.android.systemui.Dependency.DependencyProvider;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.NotificationGutsManager;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.ScrimView;
+import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.LockIcon;
@@ -38,7 +41,6 @@
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-import com.android.systemui.volume.VolumeDialogControllerImpl;
import java.util.function.Consumer;
@@ -86,10 +88,10 @@
public ScrimController createScrimController(LightBarController lightBarController,
ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim,
- LockscreenWallpaper lockscreenWallpaper,
- Consumer<Boolean> scrimVisibleListener) {
+ LockscreenWallpaper lockscreenWallpaper, Consumer<Boolean> scrimVisibleListener,
+ DozeParameters dozeParameters) {
return new ScrimController(lightBarController, scrimBehind, scrimInFront, headsUpScrim,
- scrimVisibleListener);
+ scrimVisibleListener, dozeParameters);
}
public NotificationIconAreaController createNotificationIconAreaController(Context context,
@@ -107,10 +109,11 @@
return new QSTileHost(context, statusBar, iconController);
}
- public <T> T createInstance(Class<T> classType) {
- return null;
- }
-
public void injectDependencies(ArrayMap<Object, DependencyProvider> providers,
- Context context) { }
+ Context context) {
+ providers.put(NotificationLockscreenUserManager.class,
+ () -> new NotificationLockscreenUserManager(context));
+ providers.put(NotificationGutsManager.class, () -> new NotificationGutsManager(
+ Dependency.get(NotificationLockscreenUserManager.class), context));
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
index debda21..cc2244a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
@@ -30,8 +30,6 @@
import com.android.systemui.R;
-import java.util.Arrays;
-
/**
* Class to store the policy for AOD, which comes from
* {@link android.provider.Settings.Global}
@@ -102,20 +100,6 @@
mSettingsObserver.observe();
}
- private int[] parseIntArray(final String key, final int[] defaultArray) {
- final String value = mParser.getString(key, null);
- if (value != null) {
- try {
- return Arrays.stream(value.split(":")).map(String::trim).mapToInt(
- Integer::parseInt).toArray();
- } catch (NumberFormatException e) {
- return defaultArray;
- }
- } else {
- return defaultArray;
- }
- }
-
private final class SettingsObserver extends ContentObserver {
private final Uri ALWAYS_ON_DISPLAY_CONSTANTS_URI
= Settings.Global.getUriFor(Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS);
@@ -154,10 +138,10 @@
DEFAULT_PROX_COOLDOWN_TRIGGER_MS);
proxCooldownPeriodMs = mParser.getLong(KEY_PROX_COOLDOWN_PERIOD_MS,
DEFAULT_PROX_COOLDOWN_PERIOD_MS);
- screenBrightnessArray = parseIntArray(KEY_SCREEN_BRIGHTNESS_ARRAY,
+ screenBrightnessArray = mParser.getIntArray(KEY_SCREEN_BRIGHTNESS_ARRAY,
resources.getIntArray(
R.array.config_doze_brightness_sensor_to_brightness));
- dimmingScrimArray = parseIntArray(KEY_DIMMING_SCRIM_ARRAY,
+ dimmingScrimArray = mParser.getIntArray(KEY_DIMMING_SCRIM_ARRAY,
resources.getIntArray(
R.array.config_doze_brightness_sensor_to_scrim_opacity));
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 7db118d..2f607ee 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -35,7 +35,6 @@
boolean isBlockingDoze();
void startPendingIntentDismissingKeyguard(PendingIntent intent);
- void abortPulsing();
void extendPulse();
void setAnimateWakeup(boolean animateWakeup);
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 00e8b1a..3b54e11 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -19,6 +19,7 @@
import android.app.ActivityManager;
import android.app.Dialog;
import android.app.WallpaperManager;
+import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@@ -112,11 +113,13 @@
private static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist";
private static final String GLOBAL_ACTION_KEY_ASSIST = "assist";
private static final String GLOBAL_ACTION_KEY_RESTART = "restart";
+ private static final String GLOBAL_ACTION_KEY_LOGOUT = "logout";
private final Context mContext;
private final GlobalActionsManager mWindowManagerFuncs;
private final AudioManager mAudioManager;
private final IDreamManager mDreamManager;
+ private final DevicePolicyManager mDevicePolicyManager;
private ArrayList<Action> mItems;
private ActionsDialog mDialog;
@@ -132,6 +135,7 @@
private boolean mIsWaitingForEcmExit = false;
private boolean mHasTelephony;
private boolean mHasVibrator;
+ private boolean mHasLogoutButton;
private final boolean mShowSilentToggle;
private final EmergencyAffordanceManager mEmergencyAffordanceManager;
@@ -144,6 +148,8 @@
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
mDreamManager = IDreamManager.Stub.asInterface(
ServiceManager.getService(DreamService.DREAM_SERVICE));
+ mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
// receive broadcasts
IntentFilter filter = new IntentFilter();
@@ -289,6 +295,7 @@
R.array.config_globalActionsList);
ArraySet<String> addedKeys = new ArraySet<String>();
+ mHasLogoutButton = false;
for (int i = 0; i < defaultActions.length; i++) {
String actionKey = defaultActions[i];
if (addedKeys.contains(actionKey)) {
@@ -325,6 +332,12 @@
mItems.add(getAssistAction());
} else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) {
mItems.add(new RestartAction());
+ } else if (GLOBAL_ACTION_KEY_LOGOUT.equals(actionKey)) {
+ if (mDevicePolicyManager.isLogoutButtonEnabled()
+ && getCurrentUser().id != UserHandle.USER_SYSTEM) {
+ mItems.add(new LogoutAction());
+ mHasLogoutButton = true;
+ }
} else {
Log.e(TAG, "Invalid global action key " + actionKey);
}
@@ -490,6 +503,37 @@
}
}
+ private final class LogoutAction extends SinglePressAction {
+ private LogoutAction() {
+ super(R.drawable.ic_logout, R.string.global_action_logout);
+ }
+
+ @Override
+ public boolean showDuringKeyguard() {
+ return true;
+ }
+
+ @Override
+ public boolean showBeforeProvisioning() {
+ return false;
+ }
+
+ @Override
+ public void onPress() {
+ // Add a little delay before executing, to give the dialog a chance to go away before
+ // switching user
+ mHandler.postDelayed(() -> {
+ try {
+ ActivityManager.getService().switchUser(UserHandle.USER_SYSTEM);
+ ActivityManager.getService().stopUser(getCurrentUser().id, true /*force*/,
+ null);
+ } catch (RemoteException re) {
+ Log.e(TAG, "Couldn't logout user " + re);
+ }
+ }, 500);
+ }
+ }
+
private Action getSettingsAction() {
return new SinglePressAction(R.drawable.ic_settings,
R.string.global_action_settings) {
@@ -764,7 +808,10 @@
public View getView(int position, View convertView, ViewGroup parent) {
Action action = getItem(position);
View view = action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
- if (position == 2) {
+ // When there is no logout button, only power off and restart should be in white
+ // background, thus setting division view at third item; with logout button being the
+ // third item, set the division view at fourth item instead.
+ if (position == (mHasLogoutButton ? 3 : 2)) {
HardwareUiLayout.get(parent).setDivisionView(view);
}
return view;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b99e76a..1faf981 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -25,7 +25,7 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
-import android.app.Activity;
+
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.NotificationManager;
@@ -53,7 +53,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
-import android.provider.Settings.System;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.EventLog;
@@ -77,20 +76,16 @@
import com.android.keyguard.KeyguardSecurityView;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.keyguard.LatencyTracker;
+import com.android.internal.util.LatencyTracker;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.Dependency;
import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.classifier.FalsingManager;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.statusbar.phone.FingerprintUnlockController;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.phone.StatusBarWindowManager;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -2028,12 +2023,9 @@
}
public StatusBarKeyguardViewManager registerStatusBar(StatusBar statusBar,
- ViewGroup container,
- ScrimController scrimController,
- FingerprintUnlockController fingerprintUnlockController) {
+ ViewGroup container, FingerprintUnlockController fingerprintUnlockController) {
mStatusBarKeyguardViewManager.registerStatusBar(statusBar, container,
- scrimController, fingerprintUnlockController,
- mDismissCallbackRegistry);
+ fingerprintUnlockController, mDismissCallbackRegistry);
return mStatusBarKeyguardViewManager;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index eef43d2..a984680 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -625,9 +625,7 @@
@Override
public void onTaskStackChanged() {
if (DEBUG) Log.d(TAG, "onTaskStackChanged()");
- if (!checkCurrentUserId(mContext, DEBUG)) {
- return;
- }
+
if (getState() != STATE_NO_PIP) {
boolean hasPip = false;
@@ -662,9 +660,7 @@
@Override
public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
if (DEBUG) Log.d(TAG, "onActivityPinned()");
- if (!checkCurrentUserId(mContext, DEBUG)) {
- return;
- }
+
StackInfo stackInfo = getPinnedStackInfo();
if (stackInfo == null) {
Log.w(TAG, "Cannot find pinned stack");
@@ -690,9 +686,7 @@
@Override
public void onPinnedActivityRestartAttempt(boolean clearedTask) {
if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
- if (!checkCurrentUserId(mContext, DEBUG)) {
- return;
- }
+
// If PIPed activity is launched again by Launcher or intent, make it fullscreen.
movePipToFullscreen();
}
@@ -700,9 +694,7 @@
@Override
public void onPinnedStackAnimationEnded() {
if (DEBUG) Log.d(TAG, "onPinnedStackAnimationEnded()");
- if (!checkCurrentUserId(mContext, DEBUG)) {
- return;
- }
+
switch (getState()) {
case STATE_PIP_MENU:
showPipMenu();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 5ffd785..8d50d4b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -45,6 +45,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.keyguard.KeyguardStatusView;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.Utils;
import com.android.settingslib.drawable.UserIconDrawable;
import com.android.systemui.Dependency;
@@ -431,7 +432,7 @@
@Override
public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
if (picture != null &&
- UserManager.get(mContext).isGuestUser(ActivityManager.getCurrentUser()) &&
+ UserManager.get(mContext).isGuestUser(KeyguardUpdateMonitor.getCurrentUser()) &&
!(picture instanceof UserIconDrawable)) {
picture = picture.getConstantState().newDrawable(mContext.getResources()).mutate();
picture.setColorFilter(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 4a91ee0..cdf0c0f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -63,6 +63,7 @@
private QSContainerImpl mContainer;
private int mLayoutDirection;
private QSFooter mFooter;
+ private float mLastQSExpansion = -1;
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@@ -227,6 +228,7 @@
public void setKeyguardShowing(boolean keyguardShowing) {
if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
mKeyguardShowing = keyguardShowing;
+ mLastQSExpansion = -1;
if (mQSAnimator != null) {
mQSAnimator.setOnKeyguard(keyguardShowing);
@@ -268,6 +270,10 @@
getView().setTranslationY(mKeyguardShowing ? (translationScaleY * height)
: headerTranslation);
}
+ if (expansion == mLastQSExpansion) {
+ return;
+ }
+ mLastQSExpansion = expansion;
mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
mFooter.setExpansion(mKeyguardShowing ? 1 : expansion);
int heightDiff = mQSPanel.getBottom() - mHeader.getBottom() + mHeader.getPaddingBottom()
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 9aecc68..ca9a553 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -46,7 +46,7 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.keyguard.LatencyTracker;
+import com.android.internal.util.LatencyTracker;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 3b1b2f9..663f206 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -23,14 +23,12 @@
import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
import android.app.ActivityManager;
-import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.GraphicBuffer;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
@@ -89,7 +87,6 @@
import com.android.systemui.shared.recents.view.RecentsTransition;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.stackdivider.DividerView;
-import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
import com.android.systemui.statusbar.phone.StatusBar;
import java.util.ArrayList;
@@ -156,7 +153,8 @@
// Launched from app is always the worst case (in terms of how many
// thumbnails/tasks visible)
launchState.launchedFromApp = true;
- mBackgroundLayoutAlgorithm.update(plan.getTaskStack(), EMPTY_SET, launchState);
+ mBackgroundLayoutAlgorithm.update(plan.getTaskStack(), EMPTY_SET, launchState,
+ -1 /* lastScrollPPresent */);
VisibilityReport visibilityReport =
mBackgroundLayoutAlgorithm.computeStackVisibilityReport(
stack.getTasks());
@@ -656,13 +654,6 @@
// the resize mode already.
if (ssp.setTaskWindowingModeSplitScreenPrimary(taskId, stackCreateMode, initialBounds)) {
EventBus.getDefault().send(new DockedTopTaskEvent(dragMode, initialBounds));
- showRecents(
- false /* triggeredFromAltTab */,
- dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS,
- false /* animate */,
- true /* launchedWhileDockingTask*/,
- false /* fromHome */,
- DividerView.INVALID_RECENTS_GROW_TARGET);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index cf3cae5..130a5e3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -68,7 +68,6 @@
import com.android.internal.app.AssistUtils;
import com.android.internal.os.BackgroundThread;
import com.android.systemui.Dependency;
-import com.android.systemui.R;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsImpl;
@@ -268,7 +267,7 @@
try {
return mIam.setTaskWindowingModeSplitScreenPrimary(taskId, createMode, true /* onTop */,
- false /* animate */, initialBounds);
+ false /* animate */, initialBounds, true /* showRecents */);
} catch (RemoteException e) {
e.printStackTrace();
}
@@ -372,7 +371,7 @@
if (mIam == null) return false;
try {
- return mIam.isInLockTaskMode();
+ return mIam.getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_PINNED;
} catch (RemoteException e) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 600da04..d9f79bb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -431,7 +431,7 @@
* in the stack.
*/
public void update(TaskStack stack, ArraySet<Task.TaskKey> ignoreTasksSet,
- RecentsActivityLaunchState launchState) {
+ RecentsActivityLaunchState launchState, float lastScrollPPercent) {
SystemServicesProxy ssp = Recents.getSystemServices();
// Clear the progress map
@@ -506,6 +506,8 @@
if (launchState.launchedWithAltTab) {
mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
+ } else if (0 <= lastScrollPPercent && lastScrollPPercent <= 1) {
+ mInitialScrollP = Utilities.mapRange(lastScrollPPercent, mMinScrollP, mMaxScrollP);
} else if (Recents.getConfiguration().isLowRamDevice) {
mInitialScrollP = mTaskStackLowRamLayoutAlgorithm.getInitialScrollP(mNumStackTasks,
scrollToFront);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 1197501..36c9095 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -209,6 +209,9 @@
private int mLastHeight;
private boolean mStackActionButtonVisible;
+ // Percentage of last ScrollP from the min to max scrollP that lives after configuration changes
+ private float mLastScrollPPercent;
+
// We keep track of the task view focused by user interaction and draw a frame around it in the
// grid layout.
private TaskViewFocusFrame mTaskViewFocusFrame;
@@ -327,6 +330,7 @@
mStackScroller.reset();
mStableLayoutAlgorithm.reset();
mLayoutAlgorithm.reset();
+ mLastScrollPPercent = -1;
}
// Since we always animate to the same place in (the initial state), always reset the stack
@@ -822,7 +826,7 @@
public void updateLayoutAlgorithm(boolean boundScrollToNewMinMax,
RecentsActivityLaunchState launchState) {
// Compute the min and max scroll values
- mLayoutAlgorithm.update(mStack, mIgnoreTasks, launchState);
+ mLayoutAlgorithm.update(mStack, mIgnoreTasks, launchState, mLastScrollPPercent);
if (boundScrollToNewMinMax) {
mStackScroller.boundScroll();
@@ -1150,6 +1154,8 @@
if (mTaskViewsClipDirty) {
clipTaskViews();
}
+ mLastScrollPPercent = Utilities.clamp(Utilities.unmapRange(mStackScroller.getStackScroll(),
+ mLayoutAlgorithm.mMinScrollP, mLayoutAlgorithm.mMaxScrollP), 0, 1);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index bfaa8cd..c91cdfc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -256,6 +256,9 @@
}
case MotionEvent.ACTION_MOVE: {
int activePointerIndex = ev.findPointerIndex(mActivePointerId);
+ if (activePointerIndex == -1) {
+ break;
+ }
int y = (int) ev.getY(activePointerIndex);
int x = (int) ev.getX(activePointerIndex);
if (!mIsScrolling) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 991c3c8..5fcd006 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -49,7 +49,6 @@
import android.media.MediaActionSound;
import android.net.Uri;
import android.os.AsyncTask;
-import android.os.Bundle;
import android.os.Environment;
import android.os.PowerManager;
import android.os.Process;
@@ -162,7 +161,7 @@
Matrix matrix = new Matrix();
int overlayColor = 0x40FFFFFF;
- Bitmap picture = Bitmap.createBitmap(previewWidth, previewHeight, data.image.getConfig());
+ Bitmap picture = Bitmap.createBitmap(previewWidth, previewHeight, Bitmap.Config.ARGB_8888);
matrix.setTranslate((previewWidth - mImageWidth) / 2, (previewHeight - mImageHeight) / 2);
c.setBitmap(picture);
c.drawBitmap(data.image, matrix, paint);
@@ -171,7 +170,7 @@
// Note, we can't use the preview for the small icon, since it is non-square
float scale = (float) iconSize / Math.min(mImageWidth, mImageHeight);
- Bitmap icon = Bitmap.createBitmap(iconSize, iconSize, data.image.getConfig());
+ Bitmap icon = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
matrix.setScale(scale, scale);
matrix.postTranslate((iconSize - (scale * mImageWidth)) / 2,
(iconSize - (scale * mImageHeight)) / 2);
@@ -557,25 +556,14 @@
/**
* Takes a screenshot of the current display and shows an animation.
*/
- void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible,
- int x, int y, int width, int height) {
- // We need to orient the screenshot correctly (and the Surface api seems to take screenshots
- // only in the natural orientation of the device :!)
- mDisplay.getRealMetrics(mDisplayMetrics);
- float[] dims = {mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels};
- float degrees = getDegreesForRotation(mDisplay.getRotation());
- boolean requiresRotation = (degrees > 0);
- if (requiresRotation) {
- // Get the dimensions of the device in its native orientation
- mDisplayMatrix.reset();
- mDisplayMatrix.preRotate(-degrees);
- mDisplayMatrix.mapPoints(dims);
- dims[0] = Math.abs(dims[0]);
- dims[1] = Math.abs(dims[1]);
- }
+ private void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible,
+ Rect crop) {
+ int rot = mDisplay.getRotation();
+ int width = crop.width();
+ int height = crop.height();
// Take the screenshot
- mScreenBitmap = SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
+ mScreenBitmap = SurfaceControl.screenshot(crop, width, height, rot);
if (mScreenBitmap == null) {
notifyScreenshotError(mContext, mNotificationManager,
R.string.screenshot_failed_to_capture_text);
@@ -583,29 +571,6 @@
return;
}
- if (requiresRotation) {
- // Rotate the screenshot to the current orientation
- Bitmap ss = Bitmap.createBitmap(mDisplayMetrics.widthPixels,
- mDisplayMetrics.heightPixels, Bitmap.Config.ARGB_8888,
- mScreenBitmap.hasAlpha(), mScreenBitmap.getColorSpace());
- Canvas c = new Canvas(ss);
- c.translate(ss.getWidth() / 2, ss.getHeight() / 2);
- c.rotate(degrees);
- c.translate(-dims[0] / 2, -dims[1] / 2);
- c.drawBitmap(mScreenBitmap, 0, 0, null);
- c.setBitmap(null);
- // Recycle the previous bitmap
- mScreenBitmap.recycle();
- mScreenBitmap = ss;
- }
-
- if (width != mDisplayMetrics.widthPixels || height != mDisplayMetrics.heightPixels) {
- // Crop the screenshot to selected region
- Bitmap cropped = Bitmap.createBitmap(mScreenBitmap, x, y, width, height);
- mScreenBitmap.recycle();
- mScreenBitmap = cropped;
- }
-
// Optimizations
mScreenBitmap.setHasAlpha(false);
mScreenBitmap.prepareToDraw();
@@ -617,8 +582,8 @@
void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible) {
mDisplay.getRealMetrics(mDisplayMetrics);
- takeScreenshot(finisher, statusBarVisible, navBarVisible, 0, 0, mDisplayMetrics.widthPixels,
- mDisplayMetrics.heightPixels);
+ takeScreenshot(finisher, statusBarVisible, navBarVisible,
+ new Rect(0, 0, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
}
/**
@@ -648,7 +613,7 @@
mScreenshotLayout.post(new Runnable() {
public void run() {
takeScreenshot(finisher, statusBarVisible, navBarVisible,
- rect.left, rect.top, rect.width(), rect.height());
+ rect);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 84b7015..ff0357a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -695,6 +695,11 @@
mBackgroundNormal.getVisibility() == View.VISIBLE ? 1.0f : 0.0f);
}
+ protected void updateBackgroundClipping() {
+ mBackgroundNormal.setBottomAmountClips(!isChildInGroup());
+ mBackgroundDimmed.setBottomAmountClips(!isChildInGroup());
+ }
+
protected boolean shouldHideBackground() {
return mDark;
}
@@ -901,12 +906,45 @@
contentView.setAlpha(contentAlpha);
}
+ @Override
+ protected void applyRoundness() {
+ super.applyRoundness();
+ applyBackgroundRoundness(getCurrentBackgroundRadiusTop(),
+ getCurrentBackgroundRadiusBottom());
+ }
+
+ protected void applyBackgroundRoundness(float topRadius, float bottomRadius) {
+ mBackgroundDimmed.setRoundness(topRadius, bottomRadius);
+ mBackgroundNormal.setRoundness(topRadius, bottomRadius);
+ }
+
+ @Override
+ protected void setBackgroundTop(int backgroundTop) {
+ mBackgroundDimmed.setBackgroundTop(backgroundTop);
+ mBackgroundNormal.setBackgroundTop(backgroundTop);
+ }
+
protected abstract View getContentView();
public int calculateBgColor() {
return calculateBgColor(true /* withTint */, true /* withOverRide */);
}
+ @Override
+ public void setCurrentSidePaddings(float currentSidePaddings) {
+ super.setCurrentSidePaddings(currentSidePaddings);
+ mBackgroundNormal.setCurrentSidePaddings(currentSidePaddings);
+ mBackgroundDimmed.setCurrentSidePaddings(currentSidePaddings);
+ }
+
+ @Override
+ protected boolean childNeedsClipping(View child) {
+ if (child instanceof NotificationBackgroundView && isClippingNeeded()) {
+ return true;
+ }
+ return super.childNeedsClipping(child);
+ }
+
/**
* @param withTint should a possible tint be factored in?
* @param withOverRide should the value be interpolated with {@link #mOverrideTint}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 6349275..8e1b104 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -82,6 +82,7 @@
private static final int MSG_TOGGLE_PANEL = 35 << MSG_SHIFT;
private static final int MSG_SHOW_SHUTDOWN_UI = 36 << MSG_SHIFT;
private static final int MSG_SET_TOP_APP_HIDES_STATUS_BAR = 37 << MSG_SHIFT;
+ private static final int MSG_ROTATION_PROPOSAL = 38 << MSG_SHIFT;
public static final int FLAG_EXCLUDE_NONE = 0;
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -142,6 +143,8 @@
default void handleSystemKey(int arg1) { }
default void handleShowGlobalActionsMenu() { }
default void handleShowShutdownUi(boolean isReboot, String reason) { }
+
+ default void onRotationProposal(int rotation) { }
}
@VisibleForTesting
@@ -458,6 +461,15 @@
}
}
+ @Override
+ public void onProposedRotationChanged(int rotation) {
+ synchronized (mLock) {
+ mHandler.removeMessages(MSG_ROTATION_PROPOSAL);
+ mHandler.obtainMessage(MSG_ROTATION_PROPOSAL, rotation, 0,
+ null).sendToTarget();
+ }
+ }
+
private final class H extends Handler {
private H(Looper l) {
super(l);
@@ -654,6 +666,11 @@
mCallbacks.get(i).setTopAppHidesStatusBar(msg.arg1 != 0);
}
break;
+ case MSG_ROTATION_PROPOSAL:
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mCallbacks.get(i).onRotationProposal(msg.arg1);
+ }
+ break;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 8ff950e..e04bd0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Configuration;
+import android.graphics.Path;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.ColorDrawable;
@@ -65,7 +66,6 @@
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
import com.android.systemui.statusbar.NotificationGuts.GutsContent;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
-import com.android.systemui.statusbar.notification.AboveShelfObserver;
import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.NotificationInflater;
import com.android.systemui.statusbar.notification.NotificationUtils;
@@ -102,7 +102,9 @@
private int mIconTransformContentShift;
private int mIconTransformContentShiftNoIcon;
private int mNotificationMinHeightLegacy;
+ private int mNotificationMinHeightBeforeP;
private int mMaxHeadsUpHeightLegacy;
+ private int mMaxHeadsUpHeightBeforeP;
private int mMaxHeadsUpHeight;
private int mMaxHeadsUpHeightIncreased;
private int mNotificationMinHeight;
@@ -110,6 +112,7 @@
private int mNotificationMaxHeight;
private int mNotificationAmbientHeight;
private int mIncreasedPaddingBetweenElements;
+ private boolean mMustStayOnScreen;
/** Does this row contain layouts that can adapt to row expansion */
private boolean mExpandable;
@@ -435,9 +438,10 @@
boolean customView = layout.getContractedChild().getId()
!= com.android.internal.R.id.status_bar_latest_event_content;
boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
+ boolean beforeP = mEntry.targetSdk < Build.VERSION_CODES.P;
int minHeight;
- if (customView && beforeN && !mIsSummaryWithChildren) {
- minHeight = mNotificationMinHeightLegacy;
+ if (customView && beforeP && !mIsSummaryWithChildren) {
+ minHeight = beforeN ? mNotificationMinHeightLegacy : mNotificationMinHeightBeforeP;
} else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
minHeight = mNotificationMinHeightLarge;
} else {
@@ -447,8 +451,8 @@
layout.getHeadsUpChild().getId()
!= com.android.internal.R.id.status_bar_latest_event_content;
int headsUpheight;
- if (headsUpCustom && beforeN) {
- headsUpheight = mMaxHeadsUpHeightLegacy;
+ if (headsUpCustom && beforeP) {
+ headsUpheight = beforeN ? mMaxHeadsUpHeightLegacy : mMaxHeadsUpHeightBeforeP;
} else if (mUseIncreasedHeadsUpHeight && layout == mPrivateLayout) {
headsUpheight = mMaxHeadsUpHeightIncreased;
} else {
@@ -488,6 +492,7 @@
notifyHeightChanged(false /* needsAnimation */);
}
if (isHeadsUp) {
+ mMustStayOnScreen = true;
setAboveShelf(true);
} else if (isAboveShelf() != wasAboveShelf) {
mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
@@ -514,6 +519,12 @@
addChildNotification(row, -1);
}
+ @Override
+ public void setHeadsUpIsVisible() {
+ super.setHeadsUpIsVisible();
+ mMustStayOnScreen = false;
+ }
+
/**
* Add a child notification to this view.
*
@@ -535,6 +546,7 @@
}
onChildrenCountChanged();
row.setIsChildInGroup(false, null);
+ row.setBottomRoundness(0.0f, false /* animate */);
}
@Override
@@ -563,6 +575,7 @@
mNotificationParent.updateBackgroundForGroupState();
}
updateIconVisibilities();
+ updateBackgroundClipping();
}
@Override
@@ -916,6 +929,7 @@
addView(mMenuRow.getMenuView(), menuIndex);
}
for (NotificationContentView l : mLayouts) {
+ l.initView();
l.reInflateViews();
}
mNotificationInflater.onDensityOrFontScaleChanged();
@@ -1025,6 +1039,7 @@
mKeepInParent = keepInParent;
}
+ @Override
public boolean isRemoved() {
return mRemoved;
}
@@ -1264,6 +1279,8 @@
private void initDimens() {
mNotificationMinHeightLegacy = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.notification_min_height_legacy);
+ mNotificationMinHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext,
+ R.dimen.notification_min_height_before_p);
mNotificationMinHeight = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.notification_min_height);
mNotificationMinHeightLarge = NotificationUtils.getFontScaledHeight(mContext,
@@ -1274,6 +1291,8 @@
R.dimen.notification_ambient_height);
mMaxHeadsUpHeightLegacy = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.notification_max_heads_up_height_legacy);
+ mMaxHeadsUpHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext,
+ R.dimen.notification_max_heads_up_height_before_p);
mMaxHeadsUpHeight = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.notification_max_heads_up_height);
mMaxHeadsUpHeightIncreased = NotificationUtils.getFontScaledHeight(mContext,
@@ -1752,6 +1771,7 @@
mPrivateLayout.updateExpandButtons(isExpandable());
updateChildrenHeaderAppearance();
updateChildrenVisibility();
+ applyChildrenRoundness();
}
public void updateChildrenHeaderAppearance() {
@@ -1930,7 +1950,7 @@
@Override
public boolean mustStayOnScreen() {
- return mIsHeadsUp;
+ return mIsHeadsUp && mMustStayOnScreen;
}
/**
@@ -2332,6 +2352,56 @@
}
}
+ @Override
+ protected boolean childNeedsClipping(View child) {
+ if (child instanceof NotificationContentView) {
+ NotificationContentView contentView = (NotificationContentView) child;
+ if (isClippingNeeded()) {
+ return true;
+ } else if (!hasNoRoundingAndNoPadding() && contentView.shouldClipToSidePaddings()) {
+ return true;
+ }
+ } else if (child == mChildrenContainer) {
+ if (isClippingNeeded() || ((isGroupExpanded() || isGroupExpansionChanging())
+ && getClipBottomAmount() != 0.0f && getCurrentBottomRoundness() != 0.0f)) {
+ return true;
+ }
+ } else if (child instanceof NotificationGuts) {
+ return !hasNoRoundingAndNoPadding();
+ }
+ return super.childNeedsClipping(child);
+ }
+
+ @Override
+ protected void applyRoundness() {
+ super.applyRoundness();
+ applyChildrenRoundness();
+ }
+
+ private void applyChildrenRoundness() {
+ if (mIsSummaryWithChildren) {
+ mChildrenContainer.setCurrentBottomRoundness(getCurrentBottomRoundness());
+ }
+ }
+
+ @Override
+ public Path getCustomClipPath(View child) {
+ if (child instanceof NotificationGuts) {
+ return getClipPath(true, /* ignoreTranslation */
+ false /* clipRoundedToBottom */);
+ }
+ if (child instanceof NotificationChildrenContainer) {
+ return getClipPath(false, /* ignoreTranslation */
+ true /* clipRoundedToBottom */);
+ }
+ return super.getCustomClipPath(child);
+ }
+
+ private boolean hasNoRoundingAndNoPadding() {
+ return mCurrentSidePaddings == 0 && getCurrentBottomRoundness() == 0.0f
+ && getCurrentTopRoundness() == 0.0f;
+ }
+
public boolean isShowingAmbient() {
return mShowAmbient;
}
@@ -2344,6 +2414,20 @@
}
}
+ @Override
+ public void setCurrentSidePaddings(float currentSidePaddings) {
+ if (mIsSummaryWithChildren) {
+ List<ExpandableNotificationRow> notificationChildren =
+ mChildrenContainer.getNotificationChildren();
+ int size = notificationChildren.size();
+ for (int i = 0; i < size; i++) {
+ ExpandableNotificationRow row = notificationChildren.get(i);
+ row.setCurrentSidePaddings(currentSidePaddings);
+ }
+ }
+ super.setCurrentSidePaddings(currentSidePaddings);
+ }
+
public static class NotificationViewState extends ExpandableViewState {
private final StackScrollState mOverallState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index 2556890..db19d2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -18,23 +18,58 @@
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Canvas;
import android.graphics.Outline;
+import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;
+
+import com.android.settingslib.Utils;
import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.AnimatableProperty;
+import com.android.systemui.statusbar.notification.PropertyAnimator;
+import com.android.systemui.statusbar.stack.AnimationProperties;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
/**
* Like {@link ExpandableView}, but setting an outline for the height and clipping.
*/
public abstract class ExpandableOutlineView extends ExpandableView {
+ private static final AnimatableProperty TOP_ROUNDNESS = AnimatableProperty.from(
+ "topRoundness",
+ ExpandableOutlineView::setTopRoundnessInternal,
+ ExpandableOutlineView::getCurrentTopRoundness,
+ R.id.top_roundess_animator_tag,
+ R.id.top_roundess_animator_end_tag,
+ R.id.top_roundess_animator_start_tag);
+ private static final AnimatableProperty BOTTOM_ROUNDNESS = AnimatableProperty.from(
+ "bottomRoundness",
+ ExpandableOutlineView::setBottomRoundnessInternal,
+ ExpandableOutlineView::getCurrentBottomRoundness,
+ R.id.bottom_roundess_animator_tag,
+ R.id.bottom_roundess_animator_end_tag,
+ R.id.bottom_roundess_animator_start_tag);
+ private static final AnimationProperties ROUNDNESS_PROPERTIES =
+ new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ private static final Path EMPTY_PATH = new Path();
+
private final Rect mOutlineRect = new Rect();
private boolean mCustomOutline;
private float mOutlineAlpha = -1f;
private float mOutlineRadius;
+ private boolean mAlwaysRoundBothCorners;
+ private Path mTmpPath = new Path();
+ private Path mTmpPath2 = new Path();
+ private float mCurrentBottomRoundness;
+ private float mCurrentTopRoundness;
+ private float mBottomRoundness;
+ private float mTopRoundness;
+ private int mBackgroundTop;
+ protected int mCurrentSidePaddings;
/**
* {@code true} if the children views of the {@link ExpandableOutlineView} are translated when
@@ -45,61 +80,259 @@
private final ViewOutlineProvider mProvider = new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
- int translation = mShouldTranslateContents ? (int) getTranslation() : 0;
- if (!mCustomOutline) {
- outline.setRoundRect(translation,
- mClipTopAmount,
- getWidth() + translation,
- Math.max(getActualHeight() - mClipBottomAmount, mClipTopAmount),
- mOutlineRadius);
+ if (!mCustomOutline && mCurrentTopRoundness == 0.0f
+ && mCurrentBottomRoundness == 0.0f && !mAlwaysRoundBothCorners) {
+ int translation = mShouldTranslateContents ? (int) getTranslation() : 0;
+ int left = Math.max(translation + mCurrentSidePaddings, mCurrentSidePaddings);
+ int top = mClipTopAmount + mBackgroundTop;
+ int right = getWidth() - mCurrentSidePaddings + Math.min(translation, 0);
+ int bottom = Math.max(getActualHeight() - mClipBottomAmount, top);
+ outline.setRect(left, top, right, bottom);
} else {
- outline.setRoundRect(mOutlineRect, mOutlineRadius);
+ Path clipPath = getClipPath();
+ if (clipPath != null && clipPath.isConvex()) {
+ // The path might not be convex in border cases where the view is small and
+ // clipped
+ outline.setConvexPath(clipPath);
+ }
}
outline.setAlpha(mOutlineAlpha);
}
};
+ private Path getClipPath() {
+ return getClipPath(false, /* ignoreTranslation */
+ false /* clipRoundedToBottom */);
+ }
+
+ protected Path getClipPath(boolean ignoreTranslation, boolean clipRoundedToBottom) {
+ int left;
+ int top;
+ int right;
+ int bottom;
+ int height;
+ Path intersectPath = null;
+ if (!mCustomOutline) {
+ int translation = mShouldTranslateContents && !ignoreTranslation
+ ? (int) getTranslation() : 0;
+ left = Math.max(translation + mCurrentSidePaddings, mCurrentSidePaddings);
+ top = mClipTopAmount + mBackgroundTop;
+ right = getWidth() - mCurrentSidePaddings + Math.min(translation, 0);
+ bottom = Math.max(getActualHeight(), top);
+ int intersectBottom = Math.max(getActualHeight() - mClipBottomAmount, top);
+ if (bottom != intersectBottom) {
+ if (clipRoundedToBottom) {
+ bottom = intersectBottom;
+ } else {
+ getRoundedRectPath(left, top, right,
+ intersectBottom, 0.0f,
+ 0.0f, mTmpPath2);
+ intersectPath = mTmpPath2;
+ }
+ }
+ } else {
+ left = mOutlineRect.left;
+ top = mOutlineRect.top;
+ right = mOutlineRect.right;
+ bottom = mOutlineRect.bottom;
+ left = Math.max(mCurrentSidePaddings, left);
+ right = Math.min(getWidth() - mCurrentSidePaddings, right);
+ }
+ height = bottom - top;
+ if (height == 0) {
+ return EMPTY_PATH;
+ }
+ float topRoundness = mAlwaysRoundBothCorners
+ ? mOutlineRadius : mCurrentTopRoundness * mOutlineRadius;
+ float bottomRoundness = mAlwaysRoundBothCorners
+ ? mOutlineRadius : mCurrentBottomRoundness * mOutlineRadius;
+ if (topRoundness + bottomRoundness > height) {
+ float overShoot = topRoundness + bottomRoundness - height;
+ topRoundness -= overShoot * mCurrentTopRoundness
+ / (mCurrentTopRoundness + mCurrentBottomRoundness);
+ bottomRoundness -= overShoot * mCurrentBottomRoundness
+ / (mCurrentTopRoundness + mCurrentBottomRoundness);
+ }
+ getRoundedRectPath(left, top, right, bottom, topRoundness,
+ bottomRoundness, mTmpPath);
+ Path roundedRectPath = mTmpPath;
+ if (intersectPath != null) {
+ roundedRectPath.op(intersectPath, Path.Op.INTERSECT);
+ }
+ return roundedRectPath;
+ }
+
+ protected Path getRoundedRectPath(int left, int top, int right, int bottom, float topRoundness,
+ float bottomRoundness) {
+ getRoundedRectPath(left, top, right, bottom, topRoundness, bottomRoundness,
+ mTmpPath);
+ return mTmpPath;
+ }
+
+ private void getRoundedRectPath(int left, int top, int right, int bottom, float topRoundness,
+ float bottomRoundness, Path outPath) {
+ outPath.reset();
+ int width = right - left;
+ float topRoundnessX = topRoundness;
+ float bottomRoundnessX = bottomRoundness;
+ topRoundnessX = Math.min(width / 2, topRoundnessX);
+ bottomRoundnessX = Math.min(width / 2, bottomRoundnessX);
+ if (topRoundness > 0.0f) {
+ outPath.moveTo(left, top + topRoundness);
+ outPath.quadTo(left, top, left + topRoundnessX, top);
+ outPath.lineTo(right - topRoundnessX, top);
+ outPath.quadTo(right, top, right, top + topRoundness);
+ } else {
+ outPath.moveTo(left, top);
+ outPath.lineTo(right, top);
+ }
+ if (bottomRoundness > 0.0f) {
+ outPath.lineTo(right, bottom - bottomRoundness);
+ outPath.quadTo(right, bottom, right - bottomRoundnessX, bottom);
+ outPath.lineTo(left + bottomRoundnessX, bottom);
+ outPath.quadTo(left, bottom, left, bottom - bottomRoundness);
+ } else {
+ outPath.lineTo(right, bottom);
+ outPath.lineTo(left, bottom);
+ }
+ outPath.close();
+ }
+
public ExpandableOutlineView(Context context, AttributeSet attrs) {
super(context, attrs);
setOutlineProvider(mProvider);
initDimens();
}
+ @Override
+ protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+ canvas.save();
+ if (childNeedsClipping(child)) {
+ Path clipPath = getCustomClipPath(child);
+ if (clipPath == null) {
+ clipPath = getClipPath();
+ }
+ if (clipPath != null) {
+ canvas.clipPath(clipPath);
+ }
+ }
+ boolean result = super.drawChild(canvas, child, drawingTime);
+ canvas.restore();
+ return result;
+ }
+
+ protected boolean childNeedsClipping(View child) {
+ return false;
+ }
+
+ protected boolean isClippingNeeded() {
+ return mAlwaysRoundBothCorners || mCustomOutline || getTranslation() != 0 ;
+
+ }
+
private void initDimens() {
Resources res = getResources();
mShouldTranslateContents =
res.getBoolean(R.bool.config_translateNotificationContentsOnSwipe);
mOutlineRadius = res.getDimension(R.dimen.notification_shadow_radius);
- setClipToOutline(res.getBoolean(R.bool.config_clipNotificationsToOutline));
+ mAlwaysRoundBothCorners = res.getBoolean(R.bool.config_clipNotificationsToOutline);
+ if (!mAlwaysRoundBothCorners) {
+ mOutlineRadius = res.getDimensionPixelSize(
+ Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius));
+ }
+ setClipToOutline(mAlwaysRoundBothCorners);
+ }
+
+ public void setTopRoundness(float topRoundness, boolean animate) {
+ if (mTopRoundness != topRoundness) {
+ mTopRoundness = topRoundness;
+ PropertyAnimator.setProperty(this, TOP_ROUNDNESS, topRoundness,
+ ROUNDNESS_PROPERTIES, animate);
+ }
+ }
+
+ protected void applyRoundness() {
+ invalidateOutline();
+ invalidate();
+ }
+
+ public float getCurrentBackgroundRadiusTop() {
+ return mCurrentTopRoundness * mOutlineRadius;
+ }
+
+ public float getCurrentTopRoundness() {
+ return mCurrentTopRoundness;
+ }
+
+ public float getCurrentBottomRoundness() {
+ return mCurrentBottomRoundness;
+ }
+
+ protected float getCurrentBackgroundRadiusBottom() {
+ return mCurrentBottomRoundness * mOutlineRadius;
+ }
+
+ public void setBottomRoundness(float bottomRoundness, boolean animate) {
+ if (mBottomRoundness != bottomRoundness) {
+ mBottomRoundness = bottomRoundness;
+ PropertyAnimator.setProperty(this, BOTTOM_ROUNDNESS, bottomRoundness,
+ ROUNDNESS_PROPERTIES, animate);
+ }
+ }
+
+ protected void setBackgroundTop(int backgroundTop) {
+ if (mBackgroundTop != backgroundTop) {
+ mBackgroundTop = backgroundTop;
+ invalidateOutline();
+ }
+ }
+
+ private void setTopRoundnessInternal(float topRoundness) {
+ mCurrentTopRoundness = topRoundness;
+ applyRoundness();
+ }
+
+ private void setBottomRoundnessInternal(float bottomRoundness) {
+ mCurrentBottomRoundness = bottomRoundness;
+ applyRoundness();
}
public void onDensityOrFontScaleChanged() {
initDimens();
- invalidateOutline();
+ applyRoundness();
}
@Override
public void setActualHeight(int actualHeight, boolean notifyListeners) {
+ int previousHeight = getActualHeight();
super.setActualHeight(actualHeight, notifyListeners);
- invalidateOutline();
+ if (previousHeight != actualHeight) {
+ applyRoundness();
+ }
}
@Override
public void setClipTopAmount(int clipTopAmount) {
+ int previousAmount = getClipTopAmount();
super.setClipTopAmount(clipTopAmount);
- invalidateOutline();
+ if (previousAmount != clipTopAmount) {
+ applyRoundness();
+ }
}
@Override
public void setClipBottomAmount(int clipBottomAmount) {
+ int previousAmount = getClipBottomAmount();
super.setClipBottomAmount(clipBottomAmount);
- invalidateOutline();
+ if (previousAmount != clipBottomAmount) {
+ applyRoundness();
+ }
}
protected void setOutlineAlpha(float alpha) {
if (alpha != mOutlineAlpha) {
mOutlineAlpha = alpha;
- invalidateOutline();
+ applyRoundness();
}
}
@@ -113,8 +346,7 @@
setOutlineRect(rect.left, rect.top, rect.right, rect.bottom);
} else {
mCustomOutline = false;
- setClipToOutline(false);
- invalidateOutline();
+ applyRoundness();
}
}
@@ -151,15 +383,22 @@
protected void setOutlineRect(float left, float top, float right, float bottom) {
mCustomOutline = true;
- setClipToOutline(true);
mOutlineRect.set((int) left, (int) top, (int) right, (int) bottom);
// Outlines need to be at least 1 dp
mOutlineRect.bottom = (int) Math.max(top, mOutlineRect.bottom);
mOutlineRect.right = (int) Math.max(left, mOutlineRect.right);
-
- invalidateOutline();
+ applyRoundness();
}
+ public Path getCustomClipPath(View child) {
+ return null;
+ }
+
+ public void setCurrentSidePaddings(float currentSidePaddings) {
+ mCurrentSidePaddings = (int) currentSidePaddings;
+ invalidateOutline();
+ invalidate();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index aac9af8..f762513 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -202,6 +202,10 @@
return mDark;
}
+ public boolean isRemoved() {
+ return false;
+ }
+
/**
* See {@link #setHideSensitive}. This is a variant which notifies this view in advance about
* the upcoming state of hiding sensitive notifications. It gets called at the very beginning
@@ -474,6 +478,9 @@
return false;
}
+ public void setHeadsUpIsVisible() {
+ }
+
public boolean isChildInGroup() {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index 81a99bc..68cf51c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -19,37 +19,57 @@
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
-import android.graphics.ColorFilter;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.view.View;
+import com.android.systemui.R;
+
/**
* A view that can be used for both the dimmed and normal background of an notification.
*/
public class NotificationBackgroundView extends View {
+ private final boolean mDontModifyCorners;
private Drawable mBackground;
private int mClipTopAmount;
private int mActualHeight;
private int mClipBottomAmount;
private int mTintColor;
+ private float[] mCornerRadii = new float[8];
+ private int mCurrentSidePaddings;
+ private boolean mBottomIsRounded;
+ private int mBackgroundTop;
+ private boolean mBottomAmountClips = true;
public NotificationBackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
+ mDontModifyCorners = getResources().getBoolean(
+ R.bool.config_clipNotificationsToOutline);
}
@Override
protected void onDraw(Canvas canvas) {
- draw(canvas, mBackground);
+ if (mClipTopAmount + mClipBottomAmount < mActualHeight - mBackgroundTop) {
+ canvas.save();
+ canvas.clipRect(0, mClipTopAmount, getWidth(), mActualHeight - mClipBottomAmount);
+ draw(canvas, mBackground);
+ canvas.restore();
+ }
}
private void draw(Canvas canvas, Drawable drawable) {
- int bottom = mActualHeight - mClipBottomAmount;
- if (drawable != null && bottom > mClipTopAmount) {
- drawable.setBounds(0, mClipTopAmount, getWidth(), bottom);
+ if (drawable != null) {
+ int bottom = mActualHeight;
+ if (mBottomIsRounded && mBottomAmountClips) {
+ bottom -= mClipBottomAmount;
+ }
+ drawable.setBounds(mCurrentSidePaddings, mBackgroundTop,
+ getWidth() - mCurrentSidePaddings, bottom);
drawable.draw(canvas);
}
}
@@ -87,6 +107,7 @@
unscheduleDrawable(mBackground);
}
mBackground = background;
+ mBackground.mutate();
if (mBackground != null) {
mBackground.setCallback(this);
setTint(mTintColor);
@@ -94,6 +115,7 @@
if (mBackground instanceof RippleDrawable) {
((RippleDrawable) mBackground).setForceSoftware(true);
}
+ updateBackgroundRadii();
invalidate();
}
@@ -152,4 +174,45 @@
public void setDrawableAlpha(int drawableAlpha) {
mBackground.setAlpha(drawableAlpha);
}
+
+ public void setRoundness(float topRoundness, float bottomRoundNess) {
+ mBottomIsRounded = bottomRoundNess != 0.0f;
+ mCornerRadii[0] = topRoundness;
+ mCornerRadii[1] = topRoundness;
+ mCornerRadii[2] = topRoundness;
+ mCornerRadii[3] = topRoundness;
+ mCornerRadii[4] = bottomRoundNess;
+ mCornerRadii[5] = bottomRoundNess;
+ mCornerRadii[6] = bottomRoundNess;
+ mCornerRadii[7] = bottomRoundNess;
+ updateBackgroundRadii();
+ }
+
+ public void setBottomAmountClips(boolean clips) {
+ if (clips != mBottomAmountClips) {
+ mBottomAmountClips = clips;
+ invalidate();
+ }
+ }
+
+ private void updateBackgroundRadii() {
+ if (mDontModifyCorners) {
+ return;
+ }
+ if (mBackground instanceof LayerDrawable) {
+ GradientDrawable gradientDrawable =
+ (GradientDrawable) ((LayerDrawable) mBackground).getDrawable(0);
+ gradientDrawable.setCornerRadii(mCornerRadii);
+ }
+ }
+
+ public void setCurrentSidePaddings(float currentSidePaddings) {
+ mCurrentSidePaddings = (int) currentSidePaddings;
+ invalidate();
+ }
+
+ public void setBackgroundTop(int backgroundTop) {
+ mBackgroundTop = backgroundTop;
+ invalidate();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 9e059c89..39c2131 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -24,6 +24,7 @@
import android.os.Build;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewGroup;
@@ -34,8 +35,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.HybridGroupManager;
+import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.NotificationCustomViewWrapper;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.NotificationViewWrapper;
@@ -49,6 +50,7 @@
*/
public class NotificationContentView extends FrameLayout {
+ private static final String TAG = "NotificationContentView";
public static final int VISIBLE_TYPE_CONTRACTED = 0;
public static final int VISIBLE_TYPE_EXPANDED = 1;
public static final int VISIBLE_TYPE_HEADSUP = 2;
@@ -58,9 +60,9 @@
public static final int UNDEFINED = -1;
private final Rect mClipBounds = new Rect();
- private final int mMinContractedHeight;
- private final int mNotificationContentMarginEnd;
+ private int mMinContractedHeight;
+ private int mNotificationContentMarginEnd;
private View mContractedChild;
private View mExpandedChild;
private View mHeadsUpChild;
@@ -134,15 +136,22 @@
private int mClipBottomAmount;
private boolean mIsLowPriority;
private boolean mIsContentExpandable;
+ private int mCustomViewSidePaddings;
public NotificationContentView(Context context, AttributeSet attrs) {
super(context, attrs);
mHybridGroupManager = new HybridGroupManager(getContext(), this);
+ initView();
+ }
+
+ public void initView() {
mMinContractedHeight = getResources().getDimensionPixelSize(
R.dimen.min_notification_layout_height);
mNotificationContentMarginEnd = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_content_margin_end);
+ mCustomViewSidePaddings = getResources().getDimensionPixelSize(
+ R.dimen.notification_content_custom_view_side_padding);
}
public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight,
@@ -178,7 +187,7 @@
: MeasureSpec.makeMeasureSpec(size, useExactly
? MeasureSpec.EXACTLY
: MeasureSpec.AT_MOST);
- mExpandedChild.measure(widthMeasureSpec, spec);
+ measureChildWithMargins(mExpandedChild, widthMeasureSpec, 0, spec, 0);
maxChildHeight = Math.max(maxChildHeight, mExpandedChild.getMeasuredHeight());
}
if (mContractedChild != null) {
@@ -196,22 +205,22 @@
} else {
heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
}
- mContractedChild.measure(widthMeasureSpec, heightSpec);
+ measureChildWithMargins(mContractedChild, widthMeasureSpec, 0, heightSpec, 0);
int measuredHeight = mContractedChild.getMeasuredHeight();
if (measuredHeight < mMinContractedHeight) {
heightSpec = MeasureSpec.makeMeasureSpec(mMinContractedHeight, MeasureSpec.EXACTLY);
- mContractedChild.measure(widthMeasureSpec, heightSpec);
+ measureChildWithMargins(mContractedChild, widthMeasureSpec, 0, heightSpec, 0);
}
maxChildHeight = Math.max(maxChildHeight, measuredHeight);
if (updateContractedHeaderWidth()) {
- mContractedChild.measure(widthMeasureSpec, heightSpec);
+ measureChildWithMargins(mContractedChild, widthMeasureSpec, 0, heightSpec, 0);
}
if (mExpandedChild != null
&& mContractedChild.getMeasuredHeight() > mExpandedChild.getMeasuredHeight()) {
// the Expanded child is smaller then the collapsed. Let's remeasure it.
heightSpec = MeasureSpec.makeMeasureSpec(mContractedChild.getMeasuredHeight(),
MeasureSpec.EXACTLY);
- mExpandedChild.measure(widthMeasureSpec, heightSpec);
+ measureChildWithMargins(mExpandedChild, widthMeasureSpec, 0, heightSpec, 0);
}
}
if (mHeadsUpChild != null) {
@@ -223,9 +232,9 @@
size = Math.min(size, layoutParams.height);
useExactly = true;
}
- mHeadsUpChild.measure(widthMeasureSpec,
+ measureChildWithMargins(mHeadsUpChild, widthMeasureSpec, 0,
MeasureSpec.makeMeasureSpec(size, useExactly ? MeasureSpec.EXACTLY
- : MeasureSpec.AT_MOST));
+ : MeasureSpec.AT_MOST), 0);
maxChildHeight = Math.max(maxChildHeight, mHeadsUpChild.getMeasuredHeight());
}
if (mSingleLineView != null) {
@@ -382,6 +391,38 @@
mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child,
mContainingNotification);
mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */);
+ updateMargins(child);
+ }
+
+ private void updateMargins(View child) {
+ if (child == null) {
+ return;
+ }
+ NotificationViewWrapper wrapper = getWrapperForView(child);
+ boolean isCustomView = wrapper instanceof NotificationCustomViewWrapper;
+ boolean needsMargins = isCustomView &&
+ child.getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P;
+ int padding = needsMargins ? mCustomViewSidePaddings : 0;
+ MarginLayoutParams layoutParams = (MarginLayoutParams) child.getLayoutParams();
+ layoutParams.setMarginStart(padding);
+ layoutParams.setMarginEnd(padding);
+ child.setLayoutParams(layoutParams);
+ }
+
+ private NotificationViewWrapper getWrapperForView(View child) {
+ if (child == mContractedChild) {
+ return mContractedWrapper;
+ }
+ if (child == mExpandedChild) {
+ return mExpandedWrapper;
+ }
+ if (child == mHeadsUpChild) {
+ return mHeadsUpWrapper;
+ }
+ if (child == mAmbientChild) {
+ return mAmbientWrapper;
+ }
+ return null;
}
public void setExpandedChild(View child) {
@@ -415,6 +456,7 @@
mExpandedChild = child;
mExpandedWrapper = NotificationViewWrapper.wrap(getContext(), child,
mContainingNotification);
+ updateMargins(child);
}
public void setHeadsUpChild(View child) {
@@ -448,6 +490,7 @@
mHeadsUpChild = child;
mHeadsUpWrapper = NotificationViewWrapper.wrap(getContext(), child,
mContainingNotification);
+ updateMargins(child);
}
public void setAmbientChild(View child) {
@@ -643,6 +686,13 @@
int endHeight = getViewForVisibleType(mVisibleType).getHeight();
int progress = Math.abs(mContentHeight - startHeight);
int totalDistance = Math.abs(endHeight - startHeight);
+ if (totalDistance == 0) {
+ Log.wtf(TAG, "the total transformation distance is 0"
+ + "\n StartType: " + mTransformationStartVisibleType + " height: " + startHeight
+ + "\n VisibleType: " + mVisibleType + " height: " + endHeight
+ + "\n mContentHeight: " + mContentHeight);
+ return 1.0f;
+ }
float amount = (float) progress / (float) totalDistance;
return Math.min(1.0f, amount);
}
@@ -1459,4 +1509,20 @@
}
return false;
}
+
+ public boolean shouldClipToSidePaddings() {
+ boolean needsPaddings = shouldClipToSidePaddings(getVisibleType());
+ if (mUserExpanding) {
+ needsPaddings |= shouldClipToSidePaddings(mTransformationStartVisibleType);
+ }
+ return needsPaddings;
+ }
+
+ private boolean shouldClipToSidePaddings(int visibleType) {
+ NotificationViewWrapper visibleWrapper = getVisibleWrapper(visibleType);
+ if (visibleWrapper == null) {
+ return false;
+ }
+ return visibleWrapper.shouldClipToSidePaddings();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
index f451fda..2e572e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
@@ -37,7 +37,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
-import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.Interpolators;
@@ -66,30 +65,27 @@
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
private final Set<String> mNonBlockablePkgs;
- private final NotificationPresenter mPresenter;
- // TODO: Create NotificationListContainer interface and use it instead of
- // NotificationStackScrollLayout here
- private final NotificationStackScrollLayout mStackScroller;
private final Context mContext;
private final AccessibilityManager mAccessibilityManager;
+ private final NotificationLockscreenUserManager mLockscreenUserManager;
+
// which notification is currently being longpress-examined by the user
private NotificationGuts mNotificationGutsExposed;
private NotificationMenuRowPlugin.MenuItem mGutsMenuItem;
- private final NotificationInfo.CheckSaveListener mCheckSaveListener;
- private final OnSettingsClickListener mOnSettingsClickListener;
+ private NotificationPresenter mPresenter;
+
+ // TODO: Create NotificationListContainer interface and use it instead of
+ // NotificationStackScrollLayout here
+ private NotificationStackScrollLayout mStackScroller;
+ private NotificationInfo.CheckSaveListener mCheckSaveListener;
+ private OnSettingsClickListener mOnSettingsClickListener;
private String mKeyToRemoveOnGutsClosed;
public NotificationGutsManager(
- NotificationPresenter presenter,
- NotificationStackScrollLayout stackScroller,
- NotificationInfo.CheckSaveListener checkSaveListener,
- Context context,
- OnSettingsClickListener onSettingsClickListener) {
- mPresenter = presenter;
- mStackScroller = stackScroller;
- mCheckSaveListener = checkSaveListener;
+ NotificationLockscreenUserManager lockscreenUserManager,
+ Context context) {
+ mLockscreenUserManager = lockscreenUserManager;
mContext = context;
- mOnSettingsClickListener = onSettingsClickListener;
Resources res = context.getResources();
mNonBlockablePkgs = new HashSet<>();
@@ -100,6 +96,16 @@
mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
}
+ public void setUp(NotificationPresenter presenter,
+ NotificationStackScrollLayout stackScroller,
+ NotificationInfo.CheckSaveListener checkSaveListener,
+ OnSettingsClickListener onSettingsClickListener) {
+ mPresenter = presenter;
+ mStackScroller = stackScroller;
+ mCheckSaveListener = checkSaveListener;
+ mOnSettingsClickListener = onSettingsClickListener;
+ }
+
public String getKeyToRemoveOnGutsClosed() {
return mKeyToRemoveOnGutsClosed;
}
@@ -189,7 +195,7 @@
// system user.
NotificationInfo.OnSettingsClickListener onSettingsClick = null;
if (!userHandle.equals(UserHandle.ALL)
- || mPresenter.getCurrentUserId() == UserHandle.USER_SYSTEM) {
+ || mLockscreenUserManager.getCurrentUserId() == UserHandle.USER_SYSTEM) {
onSettingsClick = (View v, NotificationChannel channel, int appUid) -> {
mMetricsLogger.action(MetricsProto.MetricsEvent.ACTION_NOTE_INFO);
guts.resetFalsingCheck();
@@ -354,7 +360,8 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.print("mKeyToRemoveOnGutsClosed: ");
+ pw.println("NotificationGutsManager state:");
+ pw.print(" mKeyToRemoveOnGutsClosed: ");
pw.println(mKeyToRemoveOnGutsClosed);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
new file mode 100644
index 0000000..6bcd174
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import static com.android.systemui.statusbar.RemoteInputController.processForRemoteInput;
+import static com.android.systemui.statusbar.phone.StatusBar.DEBUG;
+import static com.android.systemui.statusbar.phone.StatusBar.ENABLE_CHILD_NOTIFICATIONS;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+
+import com.android.systemui.statusbar.phone.NotificationListenerWithPlugins;
+
+/**
+ * This class handles listening to notification updates and passing them along to
+ * NotificationPresenter to be displayed to the user.
+ */
+public class NotificationListener extends NotificationListenerWithPlugins {
+ private static final String TAG = "NotificationListener";
+
+ private final NotificationPresenter mPresenter;
+ private final Context mContext;
+
+ public NotificationListener(NotificationPresenter presenter, Context context) {
+ mPresenter = presenter;
+ mContext = context;
+ }
+
+ @Override
+ public void onListenerConnected() {
+ if (DEBUG) Log.d(TAG, "onListenerConnected");
+ onPluginConnected();
+ final StatusBarNotification[] notifications = getActiveNotifications();
+ if (notifications == null) {
+ Log.w(TAG, "onListenerConnected unable to get active notifications.");
+ return;
+ }
+ final RankingMap currentRanking = getCurrentRanking();
+ mPresenter.getHandler().post(() -> {
+ for (StatusBarNotification sbn : notifications) {
+ mPresenter.addNotification(sbn, currentRanking);
+ }
+ });
+ }
+
+ @Override
+ public void onNotificationPosted(final StatusBarNotification sbn,
+ final RankingMap rankingMap) {
+ if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
+ if (sbn != null && !onPluginNotificationPosted(sbn, rankingMap)) {
+ mPresenter.getHandler().post(() -> {
+ processForRemoteInput(sbn.getNotification(), mContext);
+ String key = sbn.getKey();
+ mPresenter.getKeysKeptForRemoteInput().remove(key);
+ boolean isUpdate = mPresenter.getNotificationData().get(key) != null;
+ // In case we don't allow child notifications, we ignore children of
+ // notifications that have a summary, since` we're not going to show them
+ // anyway. This is true also when the summary is canceled,
+ // because children are automatically canceled by NoMan in that case.
+ if (!ENABLE_CHILD_NOTIFICATIONS
+ && mPresenter.getGroupManager().isChildInGroupWithSummary(sbn)) {
+ if (DEBUG) {
+ Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
+ }
+
+ // Remove existing notification to avoid stale data.
+ if (isUpdate) {
+ mPresenter.removeNotification(key, rankingMap);
+ } else {
+ mPresenter.getNotificationData().updateRanking(rankingMap);
+ }
+ return;
+ }
+ if (isUpdate) {
+ mPresenter.updateNotification(sbn, rankingMap);
+ } else {
+ mPresenter.addNotification(sbn, rankingMap);
+ }
+ });
+ }
+ }
+
+ @Override
+ public void onNotificationRemoved(StatusBarNotification sbn,
+ final RankingMap rankingMap) {
+ if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
+ if (sbn != null && !onPluginNotificationRemoved(sbn, rankingMap)) {
+ final String key = sbn.getKey();
+ mPresenter.getHandler().post(() -> mPresenter.removeNotification(key, rankingMap));
+ }
+ }
+
+ @Override
+ public void onNotificationRankingUpdate(final RankingMap rankingMap) {
+ if (DEBUG) Log.d(TAG, "onRankingUpdate");
+ if (rankingMap != null) {
+ RankingMap r = onPluginRankingUpdate(rankingMap);
+ mPresenter.getHandler().post(() -> mPresenter.updateNotificationRanking(r));
+ }
+ }
+
+ public void register() {
+ try {
+ registerAsSystemService(mContext,
+ new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
+ UserHandle.USER_ALL);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to register notification listener", e);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
new file mode 100644
index 0000000..644d834
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -0,0 +1,455 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.statusbar;
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.systemui.Dependency;
+import com.android.systemui.Dumpable;
+import com.android.systemui.OverviewProxyService;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Handles keeping track of the current user, profiles, and various things related to hiding
+ * contents, redacting notifications, and the lockscreen.
+ */
+public class NotificationLockscreenUserManager implements Dumpable {
+ private static final String TAG = "LockscreenUserManager";
+ private static final boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false;
+ public static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
+ public static final String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
+ = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
+
+ private final DevicePolicyManager mDevicePolicyManager;
+ private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
+ private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
+ private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
+ private final DeviceProvisionedController mDeviceProvisionedController =
+ Dependency.get(DeviceProvisionedController.class);
+ private final UserManager mUserManager;
+ private final IStatusBarService mBarService;
+
+ private boolean mShowLockscreenNotifications;
+ private boolean mAllowLockscreenRemoteInput;
+
+ protected final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+
+ if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
+ isCurrentProfile(getSendingUserId())) {
+ mUsersAllowingPrivateNotifications.clear();
+ updateLockscreenNotificationSetting();
+ mPresenter.updateNotifications();
+ } else if (Intent.ACTION_DEVICE_LOCKED_CHANGED.equals(action)) {
+ if (userId != mCurrentUserId && isCurrentProfile(userId)) {
+ mPresenter.onWorkChallengeChanged();
+ }
+ }
+ }
+ };
+
+ protected final BroadcastReceiver mBaseBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+ mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ updateCurrentProfilesCache();
+ Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
+
+ updateLockscreenNotificationSetting();
+
+ mPresenter.onUserSwitched(mCurrentUserId);
+ } else if (Intent.ACTION_USER_ADDED.equals(action)) {
+ updateCurrentProfilesCache();
+ } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+ // Start the overview connection to the launcher service
+ Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser();
+ } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
+ List<ActivityManager.RecentTaskInfo> recentTask = null;
+ try {
+ recentTask = ActivityManager.getService().getRecentTasks(1,
+ ActivityManager.RECENT_WITH_EXCLUDED,
+ mCurrentUserId).getList();
+ } catch (RemoteException e) {
+ // Abandon hope activity manager not running.
+ }
+ if (recentTask != null && recentTask.size() > 0) {
+ UserInfo user = mUserManager.getUserInfo(recentTask.get(0).userId);
+ if (user != null && user.isManagedProfile()) {
+ Toast toast = Toast.makeText(mContext,
+ R.string.managed_profile_foreground_toast,
+ Toast.LENGTH_SHORT);
+ TextView text = toast.getView().findViewById(android.R.id.message);
+ text.setCompoundDrawablesRelativeWithIntrinsicBounds(
+ R.drawable.stat_sys_managed_profile_status, 0, 0, 0);
+ int paddingPx = mContext.getResources().getDimensionPixelSize(
+ R.dimen.managed_profile_toast_padding);
+ text.setCompoundDrawablePadding(paddingPx);
+ toast.show();
+ }
+ }
+ } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
+ final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
+ final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
+ if (intentSender != null) {
+ try {
+ mContext.startIntentSender(intentSender, null, 0, 0, 0);
+ } catch (IntentSender.SendIntentException e) {
+ /* ignore */
+ }
+ }
+ if (notificationKey != null) {
+ try {
+ mBarService.onNotificationClick(notificationKey);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ }
+ }
+ }
+ };
+
+ protected final Context mContext;
+ protected final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
+
+ protected int mCurrentUserId = 0;
+ protected NotificationPresenter mPresenter;
+ protected ContentObserver mLockscreenSettingsObserver;
+ protected ContentObserver mSettingsObserver;
+
+ public NotificationLockscreenUserManager(Context context) {
+ mContext = context;
+ mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ mCurrentUserId = ActivityManager.getCurrentUser();
+ mBarService = IStatusBarService.Stub.asInterface(
+ ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ }
+
+ public void setUpWithPresenter(NotificationPresenter presenter) {
+ mPresenter = presenter;
+
+ mLockscreenSettingsObserver = new ContentObserver(mPresenter.getHandler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS or
+ // LOCK_SCREEN_SHOW_NOTIFICATIONS, so we just dump our cache ...
+ mUsersAllowingPrivateNotifications.clear();
+ mUsersAllowingNotifications.clear();
+ // ... and refresh all the notifications
+ updateLockscreenNotificationSetting();
+ mPresenter.updateNotifications();
+ }
+ };
+
+ mSettingsObserver = new ContentObserver(mPresenter.getHandler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateLockscreenNotificationSetting();
+ if (mDeviceProvisionedController.isDeviceProvisioned()) {
+ mPresenter.updateNotifications();
+ }
+ }
+ };
+
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
+ mLockscreenSettingsObserver,
+ UserHandle.USER_ALL);
+
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
+ true,
+ mLockscreenSettingsObserver,
+ UserHandle.USER_ALL);
+
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
+ mSettingsObserver);
+
+ if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT),
+ false,
+ mSettingsObserver,
+ UserHandle.USER_ALL);
+ }
+
+ IntentFilter allUsersFilter = new IntentFilter();
+ allUsersFilter.addAction(
+ DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+ allUsersFilter.addAction(Intent.ACTION_DEVICE_LOCKED_CHANGED);
+ mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
+ null, null);
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
+ filter.addAction(Intent.ACTION_USER_ADDED);
+ filter.addAction(Intent.ACTION_USER_PRESENT);
+ filter.addAction(Intent.ACTION_USER_UNLOCKED);
+ mContext.registerReceiver(mBaseBroadcastReceiver, filter);
+
+ IntentFilter internalFilter = new IntentFilter();
+ internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
+ mContext.registerReceiver(mBaseBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
+
+ updateCurrentProfilesCache();
+
+ mSettingsObserver.onChange(false); // set up
+ }
+
+ public boolean shouldShowLockscreenNotifications() {
+ return mShowLockscreenNotifications;
+ }
+
+ public boolean shouldAllowLockscreenRemoteInput() {
+ return mAllowLockscreenRemoteInput;
+ }
+
+ public boolean isCurrentProfile(int userId) {
+ synchronized (mCurrentProfiles) {
+ return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
+ }
+ }
+
+ /**
+ * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
+ * If so, notifications should be hidden.
+ */
+ public boolean shouldHideNotifications(int userId) {
+ return isLockscreenPublicMode(userId) && !userAllowsNotificationsInPublic(userId)
+ || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId));
+ }
+
+ /**
+ * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
+ * package-specific override.
+ */
+ public boolean shouldHideNotifications(String key) {
+ return isLockscreenPublicMode(mCurrentUserId)
+ && mPresenter.getNotificationData().getVisibilityOverride(key) ==
+ Notification.VISIBILITY_SECRET;
+ }
+
+ public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
+ return mShowLockscreenNotifications
+ && !mPresenter.getNotificationData().isAmbient(sbn.getKey());
+ }
+
+ private void setShowLockscreenNotifications(boolean show) {
+ mShowLockscreenNotifications = show;
+ }
+
+ private void setLockscreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
+ mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
+ }
+
+ protected void updateLockscreenNotificationSetting() {
+ final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+ 1,
+ mCurrentUserId) != 0;
+ final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(
+ null /* admin */, mCurrentUserId);
+ final boolean allowedByDpm = (dpmFlags
+ & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
+
+ setShowLockscreenNotifications(show && allowedByDpm);
+
+ if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
+ final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
+ 0,
+ mCurrentUserId) != 0;
+ final boolean remoteInputDpm =
+ (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
+
+ setLockscreenAllowRemoteInput(remoteInput && remoteInputDpm);
+ } else {
+ setLockscreenAllowRemoteInput(false);
+ }
+ }
+
+ /**
+ * Has the given user chosen to allow their private (full) notifications to be shown even
+ * when the lockscreen is in "public" (secure & locked) mode?
+ */
+ public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
+ if (userHandle == UserHandle.USER_ALL) {
+ return true;
+ }
+
+ if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
+ final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
+ final boolean allowedByDpm = adminAllowsUnredactedNotifications(userHandle);
+ final boolean allowed = allowedByUser && allowedByDpm;
+ mUsersAllowingPrivateNotifications.append(userHandle, allowed);
+ return allowed;
+ }
+
+ return mUsersAllowingPrivateNotifications.get(userHandle);
+ }
+
+ private boolean adminAllowsUnredactedNotifications(int userHandle) {
+ if (userHandle == UserHandle.USER_ALL) {
+ return true;
+ }
+ final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
+ userHandle);
+ return (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
+ }
+
+ /**
+ * Save the current "public" (locked and secure) state of the lockscreen.
+ */
+ public void setLockscreenPublicMode(boolean publicMode, int userId) {
+ mLockscreenPublicMode.put(userId, publicMode);
+ }
+
+ public boolean isLockscreenPublicMode(int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ return mLockscreenPublicMode.get(mCurrentUserId, false);
+ }
+ return mLockscreenPublicMode.get(userId, false);
+ }
+
+ /**
+ * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
+ * "public" (secure & locked) mode?
+ */
+ private boolean userAllowsNotificationsInPublic(int userHandle) {
+ if (userHandle == UserHandle.USER_ALL) {
+ return true;
+ }
+
+ if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
+ final boolean allowed = 0 != Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
+ mUsersAllowingNotifications.append(userHandle, allowed);
+ return allowed;
+ }
+
+ return mUsersAllowingNotifications.get(userHandle);
+ }
+
+ /** @return true if the entry needs redaction when on the lockscreen. */
+ public boolean needsRedaction(NotificationData.Entry ent) {
+ int userId = ent.notification.getUserId();
+
+ boolean currentUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(mCurrentUserId);
+ boolean notiUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(userId);
+ boolean redactedLockscreen = currentUserWantsRedaction || notiUserWantsRedaction;
+
+ boolean notificationRequestsRedaction =
+ ent.notification.getNotification().visibility == Notification.VISIBILITY_PRIVATE;
+ boolean userForcesRedaction = packageHasVisibilityOverride(ent.notification.getKey());
+
+ return userForcesRedaction || notificationRequestsRedaction && redactedLockscreen;
+ }
+
+ private boolean packageHasVisibilityOverride(String key) {
+ return mPresenter.getNotificationData().getVisibilityOverride(key) ==
+ Notification.VISIBILITY_PRIVATE;
+ }
+
+
+ private void updateCurrentProfilesCache() {
+ synchronized (mCurrentProfiles) {
+ mCurrentProfiles.clear();
+ if (mUserManager != null) {
+ for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
+ mCurrentProfiles.put(user.id, user);
+ }
+ }
+ }
+ }
+
+ public boolean isAnyProfilePublicMode() {
+ for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
+ if (isLockscreenPublicMode(mCurrentProfiles.valueAt(i).id)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the current user id. This can change if the user is switched.
+ */
+ public int getCurrentUserId() {
+ return mCurrentUserId;
+ }
+
+ public SparseArray<UserInfo> getCurrentProfiles() {
+ return mCurrentProfiles;
+ }
+
+ public void destroy() {
+ mContext.unregisterReceiver(mBaseBroadcastReceiver);
+ mContext.unregisterReceiver(mAllUsersReceiver);
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("NotificationLockscreenUserManager state:");
+ pw.print(" mCurrentUserId=");
+ pw.println(mCurrentUserId);
+ pw.print(" mShowLockscreenNotifications=");
+ pw.println(mShowLockscreenNotifications);
+ pw.print(" mAllowLockscreenRemoteInput=");
+ pw.println(mAllowLockscreenRemoteInput);
+ pw.print(" mCurrentProfiles=");
+ for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
+ final int userId = mCurrentProfiles.valueAt(i).id;
+ pw.print("" + userId + " ");
+ }
+ pw.println();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index e65bab2..283a6e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
package com.android.systemui.statusbar;
import android.app.Notification;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
index 99b4b07..b2604fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
@@ -88,6 +88,7 @@
private float mHorizSpaceForIcon = -1;
private int mVertSpaceForIcons = -1;
private int mIconPadding = -1;
+ private int mSidePadding;
private float mAlpha = 0f;
private float mPrevX;
@@ -175,6 +176,7 @@
final Resources res = mContext.getResources();
mHorizSpaceForIcon = res.getDimensionPixelSize(R.dimen.notification_menu_icon_size);
mVertSpaceForIcons = res.getDimensionPixelSize(R.dimen.notification_min_height);
+ mSidePadding = res.getDimensionPixelSize(R.dimen.notification_lockscreen_side_paddings);
mIconPadding = res.getDimensionPixelSize(R.dimen.notification_menu_icon_padding);
mMenuItems.clear();
// Construct the menu items based on the notification
@@ -496,8 +498,8 @@
final int count = mMenuContainer.getChildCount();
for (int i = 0; i < count; i++) {
final View v = mMenuContainer.getChildAt(i);
- final float left = i * mHorizSpaceForIcon;
- final float right = mParent.getWidth() - (mHorizSpaceForIcon * (i + 1));
+ final float left = mSidePadding + i * mHorizSpaceForIcon;
+ final float right = mParent.getWidth() - (mHorizSpaceForIcon * (i + 1)) - mSidePadding;
v.setX(showOnLeft ? left : right);
}
mOnLeft = showOnLeft;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index 1aca60c..4eca241 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -16,8 +16,11 @@
package com.android.systemui.statusbar;
import android.content.Intent;
+import android.os.Handler;
import android.service.notification.NotificationListenerService;
+import java.util.Set;
+
/**
* An abstraction of something that presents notifications, e.g. StatusBar. Contains methods
* for both querying the state of the system (some modularised piece of functionality may
@@ -25,7 +28,8 @@
* for affecting the state of the system (e.g. starting an intent, given that the presenter may
* want to perform some action before doing so).
*/
-public interface NotificationPresenter {
+public interface NotificationPresenter extends NotificationUpdateHandler,
+ NotificationData.Environment {
/**
* Returns true if the presenter is not visible. For example, it may not be necessary to do
@@ -39,11 +43,6 @@
boolean isPresenterLocked();
/**
- * Returns the current user id. This can change if the user is switched.
- */
- int getCurrentUserId();
-
- /**
* Runs the given intent. The presenter may want to run some animations or close itself when
* this happens.
*/
@@ -54,6 +53,11 @@
*/
NotificationData getNotificationData();
+ /**
+ * Returns the Handler for NotificationPresenter.
+ */
+ Handler getHandler();
+
// TODO: Create NotificationEntryManager and move this method to there.
/**
* Signals that some notifications have changed, and NotificationPresenter should update itself.
@@ -65,15 +69,33 @@
*/
void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation);
- // TODO: Create NotificationUpdateHandler and move this method to there.
- /**
- * Removes a notification.
- */
- void removeNotification(String key, NotificationListenerService.RankingMap ranking);
-
// TODO: Create NotificationEntryManager and move this method to there.
/**
* Gets the latest ranking map.
*/
NotificationListenerService.RankingMap getLatestRankingMap();
+
+ /**
+ * Called when the locked status of the device is changed for a work profile.
+ */
+ void onWorkChallengeChanged();
+
+ /**
+ * Notifications in this set are kept around when they were canceled in response to a remote
+ * input interaction. This allows us to show what you replied and allows you to continue typing
+ * into it.
+ */
+ // TODO: Create NotificationEntryManager and move this method to there.
+ Set<String> getKeysKeptForRemoteInput();
+
+ /**
+ * Called when the current user changes.
+ * @param newUserId new user id
+ */
+ void onUserSwitched(int newUserId);
+
+ /**
+ * Gets the NotificationLockscreenUserManager for this Presenter.
+ */
+ NotificationLockscreenUserManager getNotificationLockscreenUserManager();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 5557dde..75321fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -82,9 +82,7 @@
private boolean mNoAnimationsInThisFrame;
private boolean mAnimationsEnabled = true;
private boolean mShowNotificationShelf;
- private boolean mVibrationOnAnimation;
- private boolean mUserTouchingScreen;
- private boolean mTouchActive;
+ private float mFirstElementRoundness;
public NotificationShelf(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -101,24 +99,13 @@
setClipChildren(false);
setClipToPadding(false);
mShelfIcons.setShowAllIcons(false);
- mVibrationOnAnimation = mContext.getResources().getBoolean(
- R.bool.config_vibrateOnIconAnimation);
- updateVibrationOnAnimation();
mViewInvertHelper = new ViewInvertHelper(mShelfIcons,
NotificationPanelView.DOZE_ANIMATION_DURATION);
mShelfState = new ShelfState();
+ setBottomRoundness(1.0f, false /* animate */);
initDimens();
}
- private void updateVibrationOnAnimation() {
- mShelfIcons.setVibrateOnAnimation(mVibrationOnAnimation && mTouchActive);
- }
-
- public void setTouchActive(boolean touchActive) {
- mTouchActive = touchActive;
- updateVibrationOnAnimation();
- }
-
public void bind(AmbientState ambientState, NotificationStackScrollLayout hostLayout) {
mAmbientState = ambientState;
mHostLayout = hostLayout;
@@ -252,6 +239,8 @@
boolean expandingAnimated = mAmbientState.isExpansionChanging()
&& !mAmbientState.isPanelTracking();
int baseZHeight = mAmbientState.getBaseZHeight();
+ int backgroundTop = 0;
+ float firstElementRoundness = 0.0f;
while (notificationIndex < mHostLayout.getChildCount()) {
ExpandableView child = (ExpandableView) mHostLayout.getChildAt(notificationIndex);
notificationIndex++;
@@ -302,9 +291,20 @@
if (notGoneIndex != 0 || !aboveShelf) {
row.setAboveShelf(false);
}
+ if (notGoneIndex == 0) {
+ StatusBarIconView icon = row.getEntry().expandedIcon;
+ NotificationIconContainer.IconState iconState = getIconState(icon);
+ if (iconState.clampedAppearAmount == 1.0f) {
+ // only if the first icon is fully in the shelf we want to clip to it!
+ backgroundTop = (int) (row.getTranslationY() - getTranslationY());
+ firstElementRoundness = row.getCurrentTopRoundness();
+ }
+ }
notGoneIndex++;
previousColor = ownColorUntinted;
}
+ setBackgroundTop(backgroundTop);
+ setFirstElementRoundness(firstElementRoundness);
mShelfIcons.setSpeedBumpIndex(mAmbientState.getSpeedBumpIndex());
mShelfIcons.calculateIconTranslations();
mShelfIcons.applyIconStates();
@@ -325,6 +325,13 @@
}
}
+ private void setFirstElementRoundness(float firstElementRoundness) {
+ if (mFirstElementRoundness != firstElementRoundness) {
+ mFirstElementRoundness = firstElementRoundness;
+ setTopRoundness(firstElementRoundness, false /* animate */);
+ }
+ }
+
private void updateIconClipAmount(ExpandableNotificationRow row) {
float maxTop = row.getTranslationY();
StatusBarIconView icon = row.getEntry().expandedIcon;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
index 492ab44..aea0127 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
@@ -16,7 +16,6 @@
*/
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -234,7 +233,7 @@
final int defaultSnooze = mParser.getInt(KEY_DEFAULT_SNOOZE,
resources.getInteger(R.integer.config_notification_snooze_time_default));
- final int[] snoozeTimes = parseIntArray(KEY_OPTIONS,
+ final int[] snoozeTimes = mParser.getIntArray(KEY_OPTIONS,
resources.getIntArray(R.array.config_notification_snooze_times));
for (int i = 0; i < snoozeTimes.length && i < sAccessibilityActions.length; i++) {
@@ -248,21 +247,6 @@
return options;
}
- @VisibleForTesting
- int[] parseIntArray(final String key, final int[] defaultArray) {
- final String value = mParser.getString(key, null);
- if (value != null) {
- try {
- return Arrays.stream(value.split(":")).map(String::trim).mapToInt(
- Integer::parseInt).toArray();
- } catch (NumberFormatException e) {
- return defaultArray;
- }
- } else {
- return defaultArray;
- }
- }
-
private SnoozeOption createOption(int minutes, int accessibilityActionId) {
Resources res = getResources();
boolean showInHours = minutes >= 60;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUpdateHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUpdateHandler.java
new file mode 100644
index 0000000..0044194
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUpdateHandler.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+
+/**
+ * Interface for accepting notification updates from {@link NotificationListener}.
+ */
+public interface NotificationUpdateHandler {
+ /**
+ * Add a new notification and update the current notification ranking map.
+ *
+ * @param notification Notification to add
+ * @param ranking RankingMap to update with
+ */
+ void addNotification(StatusBarNotification notification,
+ NotificationListenerService.RankingMap ranking);
+
+ /**
+ * Remove a notification and update the current notification ranking map.
+ *
+ * @param key Key identifying the notification to remove
+ * @param ranking RankingMap to update with
+ */
+ void removeNotification(String key, NotificationListenerService.RankingMap ranking);
+
+ /**
+ * Update a given notification and the current notification ranking map.
+ *
+ * @param notification Updated notification
+ * @param ranking RankingMap to update with
+ */
+ void updateNotification(StatusBarNotification notification,
+ NotificationListenerService.RankingMap ranking);
+
+ /**
+ * Update with a new notification ranking map.
+ *
+ * @param ranking RankingMap to update with
+ */
+ void updateNotificationRanking(NotificationListenerService.RankingMap ranking);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index 7f28c4c..97e3d22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -19,30 +19,83 @@
import com.android.internal.util.Preconditions;
import com.android.systemui.Dependency;
import com.android.systemui.statusbar.phone.StatusBarWindowManager;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.RemoteInputView;
+import android.app.Notification;
+import android.app.RemoteInput;
+import android.content.Context;
+import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Pair;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.List;
/**
* Keeps track of the currently active {@link RemoteInputView}s.
*/
public class RemoteInputController {
+ private static final boolean ENABLE_REMOTE_INPUT =
+ SystemProperties.getBoolean("debug.enable_remote_input", true);
private final ArrayList<Pair<WeakReference<NotificationData.Entry>, Object>> mOpen
= new ArrayList<>();
private final ArrayMap<String, Object> mSpinning = new ArrayMap<>();
private final ArrayList<Callback> mCallbacks = new ArrayList<>(3);
- private final HeadsUpManager mHeadsUpManager;
+ private final Delegate mDelegate;
- public RemoteInputController(HeadsUpManager headsUpManager) {
+ public RemoteInputController(Delegate delegate) {
addCallback(Dependency.get(StatusBarWindowManager.class));
- mHeadsUpManager = headsUpManager;
+ mDelegate = delegate;
+ }
+
+ /**
+ * Adds RemoteInput actions from the WearableExtender; to be removed once more apps support this
+ * via first-class API.
+ *
+ * TODO: Remove once enough apps specify remote inputs on their own.
+ */
+ public static void processForRemoteInput(Notification n, Context context) {
+ if (!ENABLE_REMOTE_INPUT) {
+ return;
+ }
+
+ if (n.extras != null && n.extras.containsKey("android.wearable.EXTENSIONS") &&
+ (n.actions == null || n.actions.length == 0)) {
+ Notification.Action viableAction = null;
+ Notification.WearableExtender we = new Notification.WearableExtender(n);
+
+ List<Notification.Action> actions = we.getActions();
+ final int numActions = actions.size();
+
+ for (int i = 0; i < numActions; i++) {
+ Notification.Action action = actions.get(i);
+ if (action == null) {
+ continue;
+ }
+ RemoteInput[] remoteInputs = action.getRemoteInputs();
+ if (remoteInputs == null) {
+ continue;
+ }
+ for (RemoteInput ri : remoteInputs) {
+ if (ri.getAllowFreeFormInput()) {
+ viableAction = action;
+ break;
+ }
+ }
+ if (viableAction != null) {
+ break;
+ }
+ }
+
+ if (viableAction != null) {
+ Notification.Builder rebuilder = Notification.Builder.recoverBuilder(context, n);
+ rebuilder.setActions(viableAction);
+ rebuilder.build(); // will rewrite n
+ }
+ }
}
/**
@@ -114,7 +167,7 @@
}
private void apply(NotificationData.Entry entry) {
- mHeadsUpManager.setRemoteInputActive(entry, isRemoteInputActive(entry));
+ mDelegate.setRemoteInputActive(entry, isRemoteInputActive(entry));
boolean remoteInputActive = isRemoteInputActive();
int N = mCallbacks.size();
for (int i = 0; i < N; i++) {
@@ -204,9 +257,35 @@
}
}
+ public void requestDisallowLongPressAndDismiss() {
+ mDelegate.requestDisallowLongPressAndDismiss();
+ }
+
+ public void lockScrollTo(NotificationData.Entry entry) {
+ mDelegate.lockScrollTo(entry);
+ }
+
public interface Callback {
default void onRemoteInputActive(boolean active) {}
default void onRemoteInputSent(NotificationData.Entry entry) {}
}
+
+ public interface Delegate {
+ /**
+ * Activate remote input if necessary.
+ */
+ void setRemoteInputActive(NotificationData.Entry entry, boolean remoteInputActive);
+
+ /**
+ * Request that the view does not dismiss nor perform long press for the current touch.
+ */
+ void requestDisallowLongPressAndDismiss();
+
+ /**
+ * Request that the view is made visible by scrolling to it, and keep the scroll locked until
+ * the user scrolls, or {@param v} loses focus or is detached.
+ */
+ void lockScrollTo(NotificationData.Entry entry);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index a53e348..8830352 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -41,6 +41,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.colorextraction.drawable.GradientDrawable;
+import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -50,6 +51,7 @@
public class ScrimView extends View implements ConfigurationController.ConfigurationListener {
private static final String TAG = "ScrimView";
private final ColorExtractor.GradientColors mColors;
+ private int mDensity;
private boolean mDrawAsSrc;
private float mViewAlpha = 1.0f;
private ValueAnimator mAlphaAnimator;
@@ -72,6 +74,7 @@
}
};
private Runnable mChangeRunnable;
+ private int mCornerRadius;
public ScrimView(Context context) {
this(context, null);
@@ -93,6 +96,24 @@
mColors = new ColorExtractor.GradientColors();
updateScreenSize();
updateColorWithTint(false);
+ initView();
+ final Configuration currentConfig = mContext.getResources().getConfiguration();
+ mDensity = currentConfig.densityDpi;
+ }
+
+ private void initView() {
+ mCornerRadius = getResources().getDimensionPixelSize(
+ Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius));
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ int densityDpi = newConfig.densityDpi;
+ if (mDensity != densityDpi) {
+ mDensity = densityDpi;
+ initView();
+ }
}
@Override
@@ -145,6 +166,28 @@
mDrawable.draw(canvas);
canvas.restore();
}
+ // We also need to draw the rounded corners of the background
+ canvas.save();
+ canvas.clipRect(mExcludedRect.left, mExcludedRect.top,
+ mExcludedRect.left + mCornerRadius, mExcludedRect.top + mCornerRadius);
+ mDrawable.draw(canvas);
+ canvas.restore();
+ canvas.save();
+ canvas.clipRect(mExcludedRect.right - mCornerRadius, mExcludedRect.top,
+ mExcludedRect.right, mExcludedRect.top + mCornerRadius);
+ mDrawable.draw(canvas);
+ canvas.restore();
+ canvas.save();
+ canvas.clipRect(mExcludedRect.left, mExcludedRect.bottom - mCornerRadius,
+ mExcludedRect.left + mCornerRadius, mExcludedRect.bottom);
+ mDrawable.draw(canvas);
+ canvas.restore();
+ canvas.save();
+ canvas.clipRect(mExcludedRect.right - mCornerRadius,
+ mExcludedRect.bottom - mCornerRadius,
+ mExcludedRect.right, mExcludedRect.bottom);
+ mDrawable.draw(canvas);
+ canvas.restore();
}
}
}
@@ -252,6 +295,13 @@
return false;
}
+ /**
+ * It might look counterintuitive to have another method to set the alpha instead of
+ * only using {@link #setAlpha(float)}. In this case we're in a hardware layer
+ * optimizing blend modes, so it makes sense.
+ *
+ * @param alpha Gradient alpha from 0 to 1.
+ */
public void setViewAlpha(float alpha) {
if (alpha != mViewAlpha) {
mViewAlpha = alpha;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index f5c77f2..64c52ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -369,7 +369,7 @@
private void onFacetClicked(Intent intent, int index) {
String packageName = intent.getPackage();
- if (packageName == null) {
+ if (packageName == null && !intent.getCategories().contains(Intent.CATEGORY_HOME)) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 5941af2..5ba6f6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -335,8 +335,8 @@
}
@Override
- public void userSwitched(int newUserId) {
- super.userSwitched(newUserId);
+ public void onUserSwitched(int newUserId) {
+ super.onUserSwitched(newUserId);
if (mFullscreenUserSwitcher != null) {
mFullscreenUserSwitcher.onUserSwitched(newUserId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java
new file mode 100644
index 0000000..d7b211f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import android.util.FloatProperty;
+import android.util.Property;
+import android.view.View;
+
+import com.android.systemui.statusbar.stack.AnimationProperties;
+
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * An animatable property of a view. Used with {@link PropertyAnimator}
+ */
+public interface AnimatableProperty {
+ int getAnimationStartTag();
+
+ int getAnimationEndTag();
+
+ int getAnimatorTag();
+
+ Property getProperty();
+
+ static <T extends View> AnimatableProperty from(String name, BiConsumer<T, Float> setter,
+ Function<T, Float> getter, int animatorTag, int startValueTag, int endValueTag) {
+ Property<T, Float> property = new FloatProperty<T>(name) {
+
+ @Override
+ public Float get(T object) {
+ return getter.apply(object);
+ }
+
+ @Override
+ public void setValue(T object, float value) {
+ setter.accept(object, value);
+ }
+ };
+ return new AnimatableProperty() {
+ @Override
+ public int getAnimationStartTag() {
+ return startValueTag;
+ }
+
+ @Override
+ public int getAnimationEndTag() {
+ return endValueTag;
+ }
+
+ @Override
+ public int getAnimatorTag() {
+ return animatorTag;
+ }
+
+ @Override
+ public Property getProperty() {
+ return property;
+ }
+ };
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
index fc420eb..27defca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
@@ -89,6 +89,7 @@
private void transformViewInternal(MessagingLayoutTransformState mlt,
float transformationAmount, boolean to) {
+ ensureVisible();
ArrayList<MessagingGroup> ownGroups = filterHiddenGroups(
mMessagingLayout.getMessagingGroups());
ArrayList<MessagingGroup> otherGroups = filterHiddenGroups(
@@ -332,6 +333,7 @@
@Override
public void setVisible(boolean visible, boolean force) {
+ super.setVisible(visible, force);
resetTransformedView();
ArrayList<MessagingGroup> ownGroups = mMessagingLayout.getMessagingGroups();
for (int i = 0; i < ownGroups.size(); i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
index bca4b43..66682e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
+import android.os.Build;
import android.view.View;
import com.android.systemui.R;
@@ -37,6 +38,7 @@
private final Paint mGreyPaint = new Paint();
private boolean mIsLegacy;
private int mLegacyColor;
+ private boolean mBeforeP;
protected NotificationCustomViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
super(ctx, view, row);
@@ -115,4 +117,17 @@
super.setLegacy(legacy);
mIsLegacy = legacy;
}
+
+ @Override
+ public boolean shouldClipToSidePaddings() {
+ // Before P we ensure that they are now drawing inside out content bounds since we inset
+ // the view. If they target P, then we don't have that guarantee and we need to be safe.
+ return !mBeforeP;
+ }
+
+ @Override
+ public void onContentUpdated(ExpandableNotificationRow row) {
+ super.onContentUpdated(row);
+ mBeforeP = row.getEntry().targetSdk < Build.VERSION_CODES.P;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
index eb211a1..060e6d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
@@ -58,6 +58,11 @@
@Override
public boolean isDimmable() {
- return false;
+ return getCustomBackgroundColor() == 0;
+ }
+
+ @Override
+ public boolean shouldClipToSidePaddings() {
+ return true;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index fd085d9..e07112f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -265,6 +265,11 @@
updateActionOffset();
}
+ @Override
+ public boolean shouldClipToSidePaddings() {
+ return mActionsContainer != null && mActionsContainer.getVisibility() != View.GONE;
+ }
+
private void updateActionOffset() {
if (mActionsContainer != null) {
// We should never push the actions higher than they are in the headsup view.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
index af393c9..7e2336c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -61,11 +61,6 @@
return sLocationOffset[1] - sLocationBase[1];
}
- public static boolean isHapticFeedbackDisabled(Context context) {
- return Settings.System.getIntForUser(context.getContentResolver(),
- Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0;
- }
-
/**
* @param dimenId the dimen to look up
* @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index 1cd5f15..8a767bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -194,4 +194,8 @@
public int getMinLayoutHeight() {
return 0;
}
+
+ public boolean shouldClipToSidePaddings() {
+ return false;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
index 80ba943..92dcc9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
@@ -34,6 +34,19 @@
*/
public class PropertyAnimator {
+ public static <T extends View> void setProperty(final T view,
+ AnimatableProperty animatableProperty, float newEndValue,
+ AnimationProperties properties, boolean animated) {
+ int animatorTag = animatableProperty.getAnimatorTag();
+ ValueAnimator previousAnimator = ViewState.getChildTag(view, animatorTag);
+ if (previousAnimator != null || animated) {
+ startAnimation(view, animatableProperty, newEndValue, properties);
+ } else {
+ // no new animation needed, let's just apply the value
+ animatableProperty.getProperty().set(view, newEndValue);
+ }
+ }
+
public static <T extends View> void startAnimation(final T view,
AnimatableProperty animatableProperty, float newEndValue,
AnimationProperties properties) {
@@ -102,10 +115,4 @@
view.setTag(animationEndTag, newEndValue);
}
- public interface AnimatableProperty {
- int getAnimationStartTag();
- int getAnimationEndTag();
- int getAnimatorTag();
- Property getProperty();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index ad07af0..dec5303 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -95,18 +95,22 @@
public void transformViewFrom(TransformState otherState, float transformationAmount) {
mTransformedView.animate().cancel();
if (sameAs(otherState)) {
- if (mTransformedView.getVisibility() == View.INVISIBLE
- || mTransformedView.getAlpha() != 1.0f) {
- // We have the same content, lets show ourselves
- mTransformedView.setAlpha(1.0f);
- mTransformedView.setVisibility(View.VISIBLE);
- }
+ ensureVisible();
} else {
CrossFadeHelper.fadeIn(mTransformedView, transformationAmount);
}
transformViewFullyFrom(otherState, transformationAmount);
}
+ protected void ensureVisible() {
+ if (mTransformedView.getVisibility() == View.INVISIBLE
+ || mTransformedView.getAlpha() != 1.0f) {
+ // We have the same content, lets show ourselves
+ mTransformedView.setAlpha(1.0f);
+ mTransformedView.setVisibility(View.VISIBLE);
+ }
+ }
+
public void transformViewFullyFrom(TransformState otherState, float transformationAmount) {
transformViewFrom(otherState, TRANSFORM_ALL, null, transformationAmount);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 6b7397b..3f57c2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -46,10 +46,8 @@
public void dump(PrintWriter pw) {
pw.println(" DozeParameters:");
pw.print(" getDisplayStateSupported(): "); pw.println(getDisplayStateSupported());
- pw.print(" getPulseDuration(pickup=false): "); pw.println(getPulseDuration(false));
- pw.print(" getPulseDuration(pickup=true): "); pw.println(getPulseDuration(true));
- pw.print(" getPulseInDuration(pickup=false): "); pw.println(getPulseInDuration(false));
- pw.print(" getPulseInDuration(pickup=true): "); pw.println(getPulseInDuration(true));
+ pw.print(" getPulseDuration(): "); pw.println(getPulseDuration());
+ pw.print(" getPulseInDuration(): "); pw.println(getPulseInDuration());
pw.print(" getPulseInVisibleDuration(): "); pw.println(getPulseVisibleDuration());
pw.print(" getPulseOutDuration(): "); pw.println(getPulseOutDuration());
pw.print(" getPulseOnSigMotion(): "); pw.println(getPulseOnSigMotion());
@@ -81,14 +79,12 @@
return mContext.getResources().getBoolean(R.bool.doze_suspend_display_state_supported);
}
- public int getPulseDuration(boolean pickup) {
- return getPulseInDuration(pickup) + getPulseVisibleDuration() + getPulseOutDuration();
+ public int getPulseDuration() {
+ return getPulseInDuration() + getPulseVisibleDuration() + getPulseOutDuration();
}
- public int getPulseInDuration(boolean pickupOrDoubleTap) {
- return pickupOrDoubleTap
- ? getInt("doze.pulse.duration.in.pickup", R.integer.doze_pulse_duration_in_pickup)
- : getInt("doze.pulse.duration.in", R.integer.doze_pulse_duration_in);
+ public int getPulseInDuration() {
+ return getInt("doze.pulse.duration.in", R.integer.doze_pulse_duration_in);
}
public int getPulseVisibleDuration() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 8afb849..1011383 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -16,16 +16,11 @@
package com.android.systemui.statusbar.phone;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
-import android.view.animation.Interpolator;
-import com.android.systemui.Interpolators;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
@@ -40,74 +35,59 @@
private final Handler mHandler = new Handler();
private final ScrimController mScrimController;
- private final Context mContext;
-
private boolean mDozing;
private DozeHost.PulseCallback mPulseCallback;
private int mPulseReason;
- private Animator mInFrontAnimator;
- private Animator mBehindAnimator;
- private float mInFrontTarget;
- private float mBehindTarget;
- private boolean mDozingAborted;
- private boolean mWakeAndUnlocking;
private boolean mFullyPulsing;
- private float mAodFrontScrimOpacity = 0;
- private Runnable mSetDozeInFrontAlphaDelayed;
+ private final ScrimController.Callback mScrimCallback = new ScrimController.Callback() {
+ @Override
+ public void onDisplayBlanked() {
+ if (DEBUG) {
+ Log.d(TAG, "Pulse in, mDozing=" + mDozing + " mPulseReason="
+ + DozeLog.pulseReasonToString(mPulseReason));
+ }
+ if (!mDozing) {
+ return;
+ }
+
+ // Signal that the pulse is ready to turn the screen on and draw.
+ pulseStarted();
+ }
+
+ @Override
+ public void onFinished() {
+ if (DEBUG) {
+ Log.d(TAG, "Pulse in finished, mDozing=" + mDozing);
+ }
+ if (!mDozing) {
+ return;
+ }
+ mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration());
+ mHandler.postDelayed(mPulseOutExtended,
+ mDozeParameters.getPulseVisibleDurationExtended());
+ mFullyPulsing = true;
+ }
+
+ /**
+ * Transition was aborted before it was over.
+ */
+ @Override
+ public void onCancelled() {
+ pulseFinished();
+ }
+ };
public DozeScrimController(ScrimController scrimController, Context context) {
- mContext = context;
mScrimController = scrimController;
mDozeParameters = new DozeParameters(context);
}
- public void setDozing(boolean dozing, boolean animate) {
+ public void setDozing(boolean dozing) {
if (mDozing == dozing) return;
mDozing = dozing;
- mWakeAndUnlocking = false;
- if (mDozing) {
- mDozingAborted = false;
- abortAnimations();
- mScrimController.setDozeBehindAlpha(1f);
- setDozeInFrontAlpha(mDozeParameters.getAlwaysOn() ? mAodFrontScrimOpacity : 1f);
- } else {
+ if (!mDozing) {
cancelPulsing();
- if (animate) {
- startScrimAnimation(false /* inFront */, 0f /* target */,
- NotificationPanelView.DOZE_ANIMATION_DURATION,
- Interpolators.LINEAR_OUT_SLOW_IN);
- startScrimAnimation(true /* inFront */, 0f /* target */,
- NotificationPanelView.DOZE_ANIMATION_DURATION,
- Interpolators.LINEAR_OUT_SLOW_IN);
- } else {
- abortAnimations();
- mScrimController.setDozeBehindAlpha(0f);
- setDozeInFrontAlpha(0f);
- }
- }
- }
-
- /**
- * Set the opacity of the front scrim when showing AOD1
- *
- * Used to emulate lower brightness values than the hardware supports natively.
- */
- public void setAodDimmingScrim(float scrimOpacity) {
- mAodFrontScrimOpacity = scrimOpacity;
- if (mDozing && !isPulsing() && !mDozingAborted && !mWakeAndUnlocking
- && mDozeParameters.getAlwaysOn()) {
- setDozeInFrontAlpha(mAodFrontScrimOpacity);
- }
- }
-
- public void setWakeAndUnlocking() {
- // Immediately abort the doze scrims in case of wake-and-unlock
- // for pulsing so the Keyguard fade-out animation scrim can take over.
- if (!mWakeAndUnlocking) {
- mWakeAndUnlocking = true;
- mScrimController.setDozeBehindAlpha(0f);
- setDozeInFrontAlpha(0f);
}
}
@@ -118,37 +98,21 @@
}
if (!mDozing || mPulseCallback != null) {
+ if (DEBUG) {
+ Log.d(TAG, "Pulse supressed. Dozing: " + mDozeParameters + " had callback? "
+ + (mPulseCallback != null));
+ }
// Pulse suppressed.
callback.onPulseFinished();
return;
}
- // Begin pulse. Note that it's very important that the pulse finished callback
+ // Begin pulse. Note that it's very important that the pulse finished callback
// be invoked when we're done so that the caller can drop the pulse wakelock.
mPulseCallback = callback;
mPulseReason = reason;
- setDozeInFrontAlpha(1f);
- mHandler.post(mPulseIn);
- }
- /**
- * Aborts pulsing immediately.
- */
- public void abortPulsing() {
- cancelPulsing();
- if (mDozing && !mWakeAndUnlocking) {
- mScrimController.setDozeBehindAlpha(1f);
- setDozeInFrontAlpha(mDozeParameters.getAlwaysOn() && !mDozingAborted
- ? mAodFrontScrimOpacity : 1f);
- }
- }
-
- /**
- * Aborts dozing immediately.
- */
- public void abortDoze() {
- mDozingAborted = true;
- abortPulsing();
+ mScrimController.transitionTo(ScrimState.PULSING, mScrimCallback);
}
public void pulseOutNow() {
@@ -157,17 +121,6 @@
}
}
- public void onScreenTurnedOn() {
- if (isPulsing()) {
- final boolean pickupOrDoubleTap = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP
- || mPulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
- startScrimAnimation(true /* inFront */, 0f,
- mDozeParameters.getPulseInDuration(pickupOrDoubleTap),
- pickupOrDoubleTap ? Interpolators.LINEAR_OUT_SLOW_IN : Interpolators.ALPHA_OUT,
- mPulseInFinished);
- }
- }
-
public boolean isPulsing() {
return mPulseCallback != null;
}
@@ -181,11 +134,9 @@
}
private void cancelPulsing() {
- if (DEBUG) Log.d(TAG, "Cancel pulsing");
-
if (mPulseCallback != null) {
+ if (DEBUG) Log.d(TAG, "Cancel pulsing");
mFullyPulsing = false;
- mHandler.removeCallbacks(mPulseIn);
mHandler.removeCallbacks(mPulseOut);
mHandler.removeCallbacks(mPulseOutExtended);
pulseFinished();
@@ -193,151 +144,20 @@
}
private void pulseStarted() {
+ DozeLog.tracePulseStart(mPulseReason);
if (mPulseCallback != null) {
mPulseCallback.onPulseStarted();
}
}
private void pulseFinished() {
+ DozeLog.tracePulseFinish();
if (mPulseCallback != null) {
mPulseCallback.onPulseFinished();
mPulseCallback = null;
}
}
- private void abortAnimations() {
- if (mInFrontAnimator != null) {
- mInFrontAnimator.cancel();
- }
- if (mBehindAnimator != null) {
- mBehindAnimator.cancel();
- }
- }
-
- private void startScrimAnimation(final boolean inFront, float target, long duration,
- Interpolator interpolator) {
- startScrimAnimation(inFront, target, duration, interpolator, null /* endRunnable */);
- }
-
- private void startScrimAnimation(final boolean inFront, float target, long duration,
- Interpolator interpolator, final Runnable endRunnable) {
- Animator current = getCurrentAnimator(inFront);
- if (current != null) {
- float currentTarget = getCurrentTarget(inFront);
- if (currentTarget == target) {
- return;
- }
- current.cancel();
- }
- ValueAnimator anim = ValueAnimator.ofFloat(getDozeAlpha(inFront), target);
- anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float value = (float) animation.getAnimatedValue();
- setDozeAlpha(inFront, value);
- }
- });
- anim.setInterpolator(interpolator);
- anim.setDuration(duration);
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- setCurrentAnimator(inFront, null);
- if (endRunnable != null) {
- endRunnable.run();
- }
- }
- });
- anim.start();
- setCurrentAnimator(inFront, anim);
- setCurrentTarget(inFront, target);
- }
-
- private float getCurrentTarget(boolean inFront) {
- return inFront ? mInFrontTarget : mBehindTarget;
- }
-
- private void setCurrentTarget(boolean inFront, float target) {
- if (inFront) {
- mInFrontTarget = target;
- } else {
- mBehindTarget = target;
- }
- }
-
- private Animator getCurrentAnimator(boolean inFront) {
- return inFront ? mInFrontAnimator : mBehindAnimator;
- }
-
- private void setCurrentAnimator(boolean inFront, Animator animator) {
- if (inFront) {
- mInFrontAnimator = animator;
- } else {
- mBehindAnimator = animator;
- }
- }
-
- private void setDozeAlpha(boolean inFront, float alpha) {
- if (mWakeAndUnlocking) {
- return;
- }
- if (inFront) {
- mScrimController.setDozeInFrontAlpha(alpha);
- } else {
- mScrimController.setDozeBehindAlpha(alpha);
- }
- }
-
- private float getDozeAlpha(boolean inFront) {
- return inFront
- ? mScrimController.getDozeInFrontAlpha()
- : mScrimController.getDozeBehindAlpha();
- }
-
- private void setDozeInFrontAlpha(float opacity) {
- setDozeInFrontAlphaDelayed(opacity, 0 /* delay */);
-
- }
-
- private void setDozeInFrontAlphaDelayed(float opacity, long delayMs) {
- if (mSetDozeInFrontAlphaDelayed != null) {
- mHandler.removeCallbacks(mSetDozeInFrontAlphaDelayed);
- mSetDozeInFrontAlphaDelayed = null;
- }
- if (delayMs <= 0) {
- mScrimController.setDozeInFrontAlpha(opacity);
- } else {
- mHandler.postDelayed(mSetDozeInFrontAlphaDelayed = () -> {
- setDozeInFrontAlpha(opacity);
- }, delayMs);
- }
- }
-
- private final Runnable mPulseIn = new Runnable() {
- @Override
- public void run() {
- if (DEBUG) Log.d(TAG, "Pulse in, mDozing=" + mDozing + " mPulseReason="
- + DozeLog.pulseReasonToString(mPulseReason));
- if (!mDozing) return;
- DozeLog.tracePulseStart(mPulseReason);
-
- // Signal that the pulse is ready to turn the screen on and draw.
- pulseStarted();
- }
- };
-
- private final Runnable mPulseInFinished = new Runnable() {
- @Override
- public void run() {
- if (DEBUG) Log.d(TAG, "Pulse in finished, mDozing=" + mDozing);
- if (!mDozing) return;
- mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration());
- mHandler.postDelayed(mPulseOutExtended,
- mDozeParameters.getPulseVisibleDurationExtended());
- mFullyPulsing = true;
- }
- };
-
private final Runnable mPulseOutExtended = new Runnable() {
@Override
public void run() {
@@ -354,38 +174,13 @@
mHandler.removeCallbacks(mPulseOutExtended);
if (DEBUG) Log.d(TAG, "Pulse out, mDozing=" + mDozing);
if (!mDozing) return;
- startScrimAnimation(true /* inFront */, 1,
- mDozeParameters.getPulseOutDuration(),
- Interpolators.ALPHA_IN, mPulseOutFinishing);
+ mScrimController.transitionTo(ScrimState.AOD,
+ new ScrimController.Callback() {
+ @Override
+ public void onDisplayBlanked() {
+ pulseFinished();
+ }
+ });
}
};
-
- private final Runnable mPulseOutFinishing = new Runnable() {
- @Override
- public void run() {
- if (DEBUG) Log.d(TAG, "Pulse out finished");
- DozeLog.tracePulseFinish();
- if (mDozeParameters.getAlwaysOn() && mDozing) {
- // Setting power states can block rendering. For AOD, delay finishing the pulse and
- // setting the power state until the fully black scrim had time to hit the
- // framebuffer.
- mHandler.postDelayed(mPulseOutFinished, 30);
- } else {
- mPulseOutFinished.run();
- }
- }
- };
-
- private final Runnable mPulseOutFinished = new Runnable() {
- @Override
- public void run() {
- // Signal that the pulse is all finished so we can turn the screen off now.
- DozeScrimController.this.pulseFinished();
- if (mDozeParameters.getAlwaysOn()) {
- // Setting power states can happen after we push out the frame. Make sure we
- // stay fully opaque until the power state request reaches the lower levels.
- setDozeInFrontAlphaDelayed(mAodFrontScrimOpacity, 100);
- }
- }
- };
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index 91369db..a2b1013 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -26,7 +26,7 @@
import com.android.keyguard.KeyguardConstants;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.keyguard.LatencyTracker;
+import com.android.internal.util.LatencyTracker;
import com.android.systemui.Dependency;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
@@ -181,9 +181,9 @@
}
private boolean pulsingOrAod() {
- boolean pulsing = mDozeScrimController.isPulsing();
- boolean dozingWithScreenOn = mStatusBar.isDozing() && !mStatusBar.isScreenFullyOff();
- return pulsing || dozingWithScreenOn;
+ final ScrimState scrimState = mScrimController.getState();
+ return scrimState == ScrimState.AOD
+ || scrimState == ScrimState.PULSING;
}
@Override
@@ -246,15 +246,12 @@
true /* allowEnterAnimation */);
} else if (mMode == MODE_WAKE_AND_UNLOCK){
Trace.beginSection("MODE_WAKE_AND_UNLOCK");
- mDozeScrimController.abortDoze();
} else {
Trace.beginSection("MODE_WAKE_AND_UNLOCK_FROM_DREAM");
mUpdateMonitor.awakenFromDream();
}
mStatusBarWindowManager.setStatusBarFocusable(false);
mKeyguardViewMediator.onWakeAndUnlocking();
- mScrimController.setWakeAndUnlocking();
- mDozeScrimController.setWakeAndUnlocking();
if (mStatusBar.getNavigationBarView() != null) {
mStatusBar.getNavigationBarView().setWakeAndUnlocking(true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 99debee..c281379 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -102,7 +102,7 @@
return;
}
- final int activeUserId = ActivityManager.getCurrentUser();
+ final int activeUserId = KeyguardUpdateMonitor.getCurrentUser();
final boolean isSystemUser =
UserManager.isSplitSystemUser() && activeUserId == UserHandle.USER_SYSTEM;
final boolean allowDismissKeyguard = !isSystemUser && activeUserId == keyguardUserId;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 5c9446ce86..34486db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -250,7 +250,7 @@
}
break;
case STATE_FACE_UNLOCK:
- iconRes = com.android.internal.R.drawable.ic_account_circle;
+ iconRes = R.drawable.ic_account_circle;
break;
case STATE_FINGERPRINT:
// If screen is off and device asleep, use the draw on animation so the first frame
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 6d3bc1d..61b007f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -67,7 +67,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.keyguard.LatencyTracker;
+import com.android.internal.util.LatencyTracker;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index c950036..b81a3b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -80,7 +80,8 @@
@Override
protected boolean isLightsOut(int mode) {
- return super.isLightsOut(mode) || (mAutoDim && !mWallpaperVisible);
+ return super.isLightsOut(mode) || (mAutoDim && !mWallpaperVisible
+ && mode != MODE_WARNING);
}
public LightBarTransitionsController getLightTransitionsController() {
@@ -108,7 +109,9 @@
// ok, everyone, stop it right there
navButtons.animate().cancel();
- final float navButtonsAlpha = lightsOut ? 0.6f : 1f;
+ // Bump percentage by 10% if dark.
+ float darkBump = mLightTransitionsController.getCurrentDarkIntensity() / 10;
+ final float navButtonsAlpha = lightsOut ? 0.6f + darkBump : 1f;
if (!animate) {
navButtons.setAlpha(navButtonsAlpha);
@@ -130,6 +133,9 @@
for (int i = buttonDispatchers.size() - 1; i >= 0; i--) {
buttonDispatchers.valueAt(i).setDarkIntensity(darkIntensity);
}
+ if (mAutoDim) {
+ applyLightsOut(false, true);
+ }
}
private final View.OnTouchListener mLightsOutListener = new View.OnTouchListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 0f246c6..a1b49c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.statusbar.notification.NotificationUtils.isHapticFeedbackDisabled;
-
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
@@ -120,8 +118,6 @@
private float mVisualOverflowAdaption;
private boolean mDisallowNextAnimation;
private boolean mAnimationsEnabled = true;
- private boolean mVibrateOnAnimation;
- private Vibrator mVibrator;
private ArrayMap<String, ArrayList<StatusBarIcon>> mReplacingIcons;
private int mDarkOffsetX;
@@ -129,7 +125,6 @@
super(context, attrs);
initDimens();
setWillNotDraw(!DEBUG);
- mVibrator = mContext.getSystemService(Vibrator.class);
}
private void initDimens() {
@@ -209,7 +204,7 @@
mAddAnimationStartIndex = Math.min(mAddAnimationStartIndex, childIndex);
}
}
- if (mDark && child instanceof StatusBarIconView) {
+ if (child instanceof StatusBarIconView) {
((StatusBarIconView) child).setDark(mDark, false, 0);
}
}
@@ -497,10 +492,6 @@
return width - (getWidth() - getActualPaddingStart() - getActualPaddingEnd()) > 0;
}
- public void setVibrateOnAnimation(boolean vibrateOnAnimation) {
- mVibrateOnAnimation = vibrateOnAnimation;
- }
-
public int getIconSize() {
return mIconSize;
}
@@ -608,39 +599,14 @@
} else {
super.applyToView(view);
}
- boolean wasInShelf = icon.isInShelf();
boolean inShelf = iconAppearAmount == 1.0f;
icon.setIsInShelf(inShelf);
- if (shouldVibrateChange(wasInShelf != inShelf)) {
- AsyncTask.execute(
- () -> mVibrator.vibrate(VibrationEffect.get(
- VibrationEffect.EFFECT_TICK)));
- }
}
justAdded = false;
justReplaced = false;
needsCannedAnimation = false;
}
- private boolean shouldVibrateChange(boolean inShelfChanged) {
- if (!mVibrateOnAnimation) {
- return false;
- }
- if (justAdded) {
- return false;
- }
- if (!mAnimationsEnabled) {
- return false;
- }
- if (!inShelfChanged) {
- return false;
- }
- if (isHapticFeedbackDisabled(mContext)) {
- return false;
- }
- return true;
- }
-
public boolean hasCustomTransformHeight() {
return isLastExpandIcon && customTransformHeight != NO_VALUE;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index fff6abe..61dd22f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -239,6 +239,7 @@
private ValueAnimator mDarkAnimator;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private boolean mUserSetupComplete;
+ private int mQsNotificationTopPadding;
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -307,6 +308,8 @@
R.dimen.max_notification_fadeout_height);
mIndicationBottomPadding = getResources().getDimensionPixelSize(
R.dimen.keyguard_indication_bottom_padding);
+ mQsNotificationTopPadding = getResources().getDimensionPixelSize(
+ R.dimen.qs_notification_keyguard_padding);
}
public void updateResources() {
@@ -503,7 +506,8 @@
if (suppressedSummary) {
continue;
}
- if (!mStatusBar.shouldShowOnKeyguard(row.getStatusBarNotification())) {
+ if (!mStatusBar.getNotificationLockscreenUserManager().shouldShowOnKeyguard(
+ row.getStatusBarNotification())) {
continue;
}
if (row.isRemoved()) {
@@ -818,7 +822,7 @@
private float getQsExpansionFraction() {
return Math.min(1f, (mQsExpansionHeight - mQsMinExpansionHeight)
- / (getTempQsMaxExpansion() - mQsMinExpansionHeight));
+ / (mQsMaxExpansionHeight - mQsMinExpansionHeight));
}
@Override
@@ -1361,7 +1365,7 @@
// take the maximum and linearly interpolate with the panel expansion for a nice motion.
int maxNotifications = mClockPositionResult.stackScrollerPadding
- mClockPositionResult.stackScrollerPaddingAdjustment;
- int maxQs = getTempQsMaxExpansion();
+ int maxQs = mQsMaxExpansionHeight + mQsNotificationTopPadding;
int max = mStatusBarState == StatusBarState.KEYGUARD
? Math.max(maxNotifications, maxQs)
: maxQs;
@@ -1375,7 +1379,7 @@
// from a scrolled quick settings.
return interpolate(getQsExpansionFraction(),
mNotificationStackScroller.getIntrinsicPadding(),
- mQsMaxExpansionHeight);
+ mQsMaxExpansionHeight + mQsNotificationTopPadding);
} else {
return mQsExpansionHeight;
}
@@ -1544,7 +1548,7 @@
/ (panelHeightQsExpanded - panelHeightQsCollapsed);
}
setQsExpansion(mQsMinExpansionHeight
- + t * (getTempQsMaxExpansion() - mQsMinExpansionHeight));
+ + t * (mQsMaxExpansionHeight - mQsMinExpansionHeight));
}
updateExpandedHeight(expandedHeight);
updateHeader();
@@ -1566,14 +1570,6 @@
}
}
- /**
- * @return a temporary override of {@link #mQsMaxExpansionHeight}, which is needed when
- * collapsing QS / the panel when QS was scrolled
- */
- private int getTempQsMaxExpansion() {
- return mQsMaxExpansionHeight;
- }
-
private int calculatePanelHeightShade() {
int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin();
int maxHeight = mNotificationStackScroller.getHeight() - emptyBottomMargin
@@ -1596,6 +1592,10 @@
}
int maxQsHeight = mQsMaxExpansionHeight;
+ if (mKeyguardShowing) {
+ maxQsHeight += mQsNotificationTopPadding;
+ }
+
// If an animation is changing the size of the QS panel, take the animated value.
if (mQsSizeChangeAnimator != null) {
maxQsHeight = (int) mQsSizeChangeAnimator.getAnimatedValue();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index afe5c91..2fc22ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.statusbar.notification.NotificationUtils.isHapticFeedbackDisabled;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -25,7 +23,9 @@
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.os.AsyncTask;
+import android.os.Handler;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.VibrationEffect;
@@ -42,7 +42,7 @@
import android.widget.FrameLayout;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.keyguard.LatencyTracker;
+import com.android.internal.util.LatencyTracker;
import com.android.systemui.DejankUtils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -50,7 +50,6 @@
import com.android.systemui.doze.DozeLog;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.io.FileDescriptor;
@@ -66,6 +65,7 @@
private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
private boolean mPanelUpdateWhenAnimatorEnds;
private boolean mVibrateOnOpening;
+ private boolean mVibrationEnabled;
private final void logf(String fmt, Object... args) {
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -108,6 +108,12 @@
private FlingAnimationUtils mFlingAnimationUtilsDismissing;
private FalsingManager mFalsingManager;
private final Vibrator mVibrator;
+ final private ContentObserver mVibrationObserver = new ContentObserver(Handler.getMain()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateHapticFeedBackEnabled();
+ }
+ };
/**
* Whether an instant expand request is currently pending and we are just waiting for layout.
@@ -212,6 +218,15 @@
mVibrator = mContext.getSystemService(Vibrator.class);
mVibrateOnOpening = mContext.getResources().getBoolean(
R.bool.config_vibrateOnIconAnimation);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED), true,
+ mVibrationObserver);
+ mVibrationObserver.onChange(false /* selfChange */);
+ }
+
+ public void updateHapticFeedBackEnabled() {
+ mVibrationEnabled = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) != 0;
}
protected void loadDimens() {
@@ -403,7 +418,7 @@
runPeekAnimation(INITIAL_OPENING_PEEK_DURATION, getOpeningHeight(),
false /* collapseWhenFinished */);
notifyBarPanelExpansionChanged();
- if (mVibrateOnOpening && !isHapticFeedbackDisabled(mContext)) {
+ if (mVibrateOnOpening && mVibrationEnabled) {
AsyncTask.execute(() ->
mVibrator.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_TICK, false)));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 09fe579..f41cb29 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -615,6 +615,7 @@
.addCategory(Intent.CATEGORY_BROWSABLE)
.addCategory("unique:" + System.currentTimeMillis())
.putExtra(Intent.EXTRA_PACKAGE_NAME, appInfo.packageName)
+ .putExtra(Intent.EXTRA_VERSION_CODE, (int) (appInfo.versionCode & 0x7fffffff))
.putExtra(Intent.EXTRA_VERSION_CODE, appInfo.versionCode)
.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, pendingIntent);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 702afa3..3a36776 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -25,7 +25,9 @@
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Handler;
import android.os.Trace;
+import android.util.Log;
import android.util.MathUtils;
import android.view.View;
import android.view.ViewGroup;
@@ -34,12 +36,14 @@
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.colorextraction.ColorExtractor.OnColorsChangedListener;
import com.android.internal.graphics.ColorUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dependency;
+import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -47,7 +51,10 @@
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.stack.ViewState;
+import com.android.systemui.util.wakelock.DelayedWakeLock;
+import com.android.systemui.util.wakelock.WakeLock;
+import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.function.Consumer;
@@ -56,33 +63,54 @@
* security method gets shown).
*/
public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
- OnHeadsUpChangedListener, OnColorsChangedListener {
+ OnHeadsUpChangedListener, OnColorsChangedListener, Dumpable {
+
+ private static final String TAG = "ScrimController";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
public static final long ANIMATION_DURATION = 220;
public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR
= new PathInterpolator(0f, 0, 0.7f, 1f);
public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR_LOCKED
= new PathInterpolator(0.3f, 0f, 0.8f, 1f);
- // Default alpha value for most scrims, if unsure use this constant
+ /**
+ * Default alpha value for most scrims.
+ */
public static final float GRADIENT_SCRIM_ALPHA = 0.45f;
- // A scrim varies its opacity based on a busyness factor, for example
- // how many notifications are currently visible.
+ /**
+ * A scrim varies its opacity based on a busyness factor, for example
+ * how many notifications are currently visible.
+ */
public static final float GRADIENT_SCRIM_ALPHA_BUSY = 0.70f;
+ /**
+ * The most common scrim, the one under the keyguard.
+ */
protected static final float SCRIM_BEHIND_ALPHA_KEYGUARD = GRADIENT_SCRIM_ALPHA;
+ /**
+ * We fade out the bottom scrim when the bouncer is visible.
+ */
protected static final float SCRIM_BEHIND_ALPHA_UNLOCKING = 0.2f;
- private static final float SCRIM_IN_FRONT_ALPHA = GRADIENT_SCRIM_ALPHA_BUSY;
- private static final float SCRIM_IN_FRONT_ALPHA_LOCKED = GRADIENT_SCRIM_ALPHA_BUSY;
- private static final int TAG_KEY_ANIM = R.id.scrim;
+ /**
+ * Opacity of the scrim behind the bouncer (the one doing actual background protection.)
+ */
+ protected static final float SCRIM_IN_FRONT_ALPHA_LOCKED = GRADIENT_SCRIM_ALPHA_BUSY;
+
+ static final int TAG_KEY_ANIM = R.id.scrim;
+ static final int TAG_KEY_ANIM_BLANK = R.id.scrim_blanking;
private static final int TAG_KEY_ANIM_TARGET = R.id.scrim_target;
private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
private static final int TAG_END_ALPHA = R.id.scrim_alpha_end;
private static final float NOT_INITIALIZED = -1;
- private final LightBarController mLightBarController;
+ private ScrimState mState = ScrimState.UNINITIALIZED;
+ private final Context mContext;
protected final ScrimView mScrimBehind;
protected final ScrimView mScrimInFront;
- private final UnlockMethodCache mUnlockMethodCache;
private final View mHeadsUpScrim;
+ private final LightBarController mLightBarController;
+ private final UnlockMethodCache mUnlockMethodCache;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final DozeParameters mDozeParameters;
private final SysuiColorExtractor mColorExtractor;
private GradientColors mLockColors;
@@ -94,61 +122,53 @@
protected float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
protected float mScrimBehindAlphaUnlocking = SCRIM_BEHIND_ALPHA_UNLOCKING;
- protected boolean mKeyguardShowing;
private float mFraction;
private boolean mDarkenWhileDragging;
- protected boolean mBouncerShowing;
- protected boolean mBouncerIsKeyguard = false;
- private boolean mWakeAndUnlocking;
protected boolean mAnimateChange;
private boolean mUpdatePending;
private boolean mTracking;
private boolean mAnimateKeyguardFadingOut;
- protected long mDurationOverride = -1;
+ protected long mAnimationDuration = -1;
private long mAnimationDelay;
private Runnable mOnAnimationFinished;
private boolean mDeferFinishedListener;
private final Interpolator mInterpolator = new DecelerateInterpolator();
- private boolean mDozing;
- private float mDozeInFrontAlpha;
- private float mDozeBehindAlpha;
private float mCurrentInFrontAlpha = NOT_INITIALIZED;
private float mCurrentBehindAlpha = NOT_INITIALIZED;
- private float mCurrentHeadsUpAlpha = NOT_INITIALIZED;
+ private int mCurrentInFrontTint;
+ private int mCurrentBehindTint;
private int mPinnedHeadsUpCount;
private float mTopHeadsUpDragAmount;
private View mDraggedHeadsUpView;
- private boolean mForceHideScrims;
- private boolean mSkipFirstFrame;
- private boolean mDontAnimateBouncerChanges;
private boolean mKeyguardFadingOutInProgress;
- private boolean mAnimatingDozeUnlock;
private ValueAnimator mKeyguardFadeoutAnimation;
- /** Wake up from AOD transition is starting; need fully opaque front scrim */
- private boolean mWakingUpFromAodStarting;
- /** Wake up from AOD transition is in progress; need black tint */
- private boolean mWakingUpFromAodInProgress;
- /** Wake up from AOD transition is animating; need to reset when animation finishes */
- private boolean mWakingUpFromAodAnimationRunning;
- private boolean mScrimsVisble;
+ private boolean mScrimsVisible;
private final Consumer<Boolean> mScrimVisibleListener;
+ private boolean mBlankScreen;
+ private boolean mScreenBlankingCallbackCalled;
+ private Callback mCallback;
+
+ private final WakeLock mWakeLock;
+ private boolean mWakeLockHeld;
public ScrimController(LightBarController lightBarController, ScrimView scrimBehind,
- ScrimView scrimInFront, View headsUpScrim,
- Consumer<Boolean> scrimVisibleListener) {
+ ScrimView scrimInFront, View headsUpScrim, Consumer<Boolean> scrimVisibleListener,
+ DozeParameters dozeParameters) {
mScrimBehind = scrimBehind;
mScrimInFront = scrimInFront;
mHeadsUpScrim = headsUpScrim;
mScrimVisibleListener = scrimVisibleListener;
- final Context context = scrimBehind.getContext();
- mUnlockMethodCache = UnlockMethodCache.getInstance(context);
- mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
+ mContext = scrimBehind.getContext();
+ mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
+ mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
mLightBarController = lightBarController;
- mScrimBehindAlphaResValue = context.getResources().getFloat(R.dimen.scrim_behind_alpha);
+ mScrimBehindAlphaResValue = mContext.getResources().getFloat(R.dimen.scrim_behind_alpha);
+ mWakeLock = createWakeLock();
// Scrim alpha is initially set to the value on the resource but might be changed
// to make sure that text on top of it is legible.
mScrimBehindAlpha = mScrimBehindAlphaResValue;
+ mDozeParameters = dozeParameters;
mColorExtractor = Dependency.get(SysuiColorExtractor.class);
mColorExtractor.addOnColorsChangedListener(this);
@@ -158,22 +178,90 @@
ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
mNeedsDrawableColorUpdate = true;
+ final ScrimState[] states = ScrimState.values();
+ for (int i = 0; i < states.length; i++) {
+ states[i].init(mScrimInFront, mScrimBehind, mDozeParameters);
+ states[i].setScrimBehindAlphaKeyguard(mScrimBehindAlphaKeyguard);
+ }
+ mState = ScrimState.UNINITIALIZED;
+
updateHeadsUpScrim(false);
updateScrims();
}
- public void setKeyguardShowing(boolean showing) {
- mKeyguardShowing = showing;
+ public void transitionTo(ScrimState state) {
+ transitionTo(state, null);
+ }
- // Showing/hiding the keyguard means that scrim colors have to be switched
- mNeedsDrawableColorUpdate = true;
- scheduleUpdate();
+ public void transitionTo(ScrimState state, Callback callback) {
+ if (state == mState) {
+ return;
+ } else if (DEBUG) {
+ Log.d(TAG, "State changed to: " + state);
+ }
+
+ if (state == ScrimState.UNINITIALIZED) {
+ throw new IllegalArgumentException("Cannot change to UNINITIALIZED.");
+ }
+
+ if (mCallback != null) {
+ mCallback.onCancelled();
+ }
+ mCallback = callback;
+
+ state.prepare(mState);
+ mScreenBlankingCallbackCalled = false;
+ mAnimationDelay = 0;
+ mBlankScreen = state.getBlanksScreen();
+ mAnimateChange = state.getAnimateChange();
+ mAnimationDuration = state.getAnimationDuration();
+ mCurrentInFrontTint = state.getFrontTint();
+ mCurrentBehindTint = state.getBehindTint();
+ mCurrentInFrontAlpha = state.getFrontAlpha();
+ mCurrentBehindAlpha = state.getBehindAlpha();
+
+ // Showing/hiding the keyguard means that scrim colors have to be switched, not necessary
+ // to do the same when you're just showing the brightness mirror.
+ mNeedsDrawableColorUpdate = state != ScrimState.BRIGHTNESS_MIRROR;
+
+ if (mKeyguardFadeoutAnimation != null) {
+ mKeyguardFadeoutAnimation.cancel();
+ }
+
+ mState = state;
+
+ // Do not let the device sleep until we're done with all animations
+ if (!mWakeLockHeld) {
+ if (mWakeLock != null) {
+ mWakeLockHeld = true;
+ mWakeLock.acquire();
+ } else {
+ Log.w(TAG, "Cannot hold wake lock, it has not been set yet");
+ }
+ }
+
+ if (!mKeyguardUpdateMonitor.needsSlowUnlockTransition()) {
+ scheduleUpdate();
+ } else {
+ // In case the user isn't unlocked, make sure to delay a bit because the system is hosed
+ // with too many things at this case, in order to not skip the initial frames.
+ mScrimInFront.postOnAnimationDelayed(this::scheduleUpdate, 16);
+ mAnimationDelay = StatusBar.FADE_KEYGUARD_START_DELAY;
+ }
+ }
+
+ public ScrimState getState() {
+ return mState;
}
protected void setScrimBehindValues(float scrimBehindAlphaKeyguard,
float scrimBehindAlphaUnlocking) {
mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
mScrimBehindAlphaUnlocking = scrimBehindAlphaUnlocking;
+ ScrimState[] states = ScrimState.values();
+ for (int i = 0; i < states.length; i++) {
+ states[i].setScrimBehindAlphaKeyguard(scrimBehindAlphaKeyguard);
+ }
scheduleUpdate();
}
@@ -186,131 +274,59 @@
mTracking = false;
}
+ /**
+ * Current state of the shade expansion when pulling it from the top.
+ * This value is 1 when on top of the keyguard and goes to 0 as the user drags up.
+ *
+ * The expansion fraction is tied to the scrim opacity.
+ *
+ * @param fraction From 0 to 1 where 0 means collapse and 1 expanded.
+ */
public void setPanelExpansion(float fraction) {
if (mFraction != fraction) {
mFraction = fraction;
- scheduleUpdate();
+
+ if (mState == ScrimState.UNLOCKED) {
+ // Darken scrim as you pull down the shade when unlocked
+ float behindFraction = getInterpolatedFraction();
+ behindFraction = (float) Math.pow(behindFraction, 0.8f);
+ mCurrentBehindAlpha = behindFraction * mScrimBehindAlphaKeyguard;
+ mCurrentInFrontAlpha = 0;
+ } else if (mState == ScrimState.KEYGUARD) {
+ if (mUpdatePending) {
+ return;
+ }
+
+ // Either darken of make the scrim transparent when you
+ // pull down the shade
+ float interpolatedFract = getInterpolatedFraction();
+ if (mDarkenWhileDragging) {
+ mCurrentBehindAlpha = MathUtils.lerp(mScrimBehindAlphaUnlocking,
+ mScrimBehindAlphaKeyguard, interpolatedFract);
+ mCurrentInFrontAlpha = (1f - interpolatedFract) * SCRIM_IN_FRONT_ALPHA_LOCKED;
+ } else {
+ mCurrentBehindAlpha = MathUtils.lerp(0 /* start */, mScrimBehindAlphaKeyguard,
+ interpolatedFract);
+ mCurrentInFrontAlpha = 0;
+ }
+ } else {
+ Log.w(TAG, "Invalid state, cannot set panel expansion when: " + mState);
+ return;
+ }
+
if (mPinnedHeadsUpCount != 0) {
updateHeadsUpScrim(false);
}
- if (mKeyguardFadeoutAnimation != null && mTracking) {
- mKeyguardFadeoutAnimation.cancel();
- }
+
+ updateScrim(false /* animate */, mScrimInFront, mCurrentInFrontAlpha);
+ updateScrim(false /* animate */, mScrimBehind, mCurrentBehindAlpha);
}
}
- public void setBouncerShowing(boolean showing) {
- mBouncerShowing = showing;
- mAnimateChange = !mTracking && !mDontAnimateBouncerChanges && !mKeyguardFadingOutInProgress;
- scheduleUpdate();
- }
-
- /** Prepares the wakeUpFromAod animation (while turning on screen); Forces black scrims. */
- public void prepareWakeUpFromAod() {
- if (mWakingUpFromAodInProgress) {
- return;
- }
- mWakingUpFromAodInProgress = true;
- mWakingUpFromAodStarting = true;
- mAnimateChange = false;
- scheduleUpdate();
- onPreDraw();
- }
-
- /** Starts the wakeUpFromAod animation (once screen is on); animate to transparent scrims. */
- public void wakeUpFromAod() {
- if (mWakeAndUnlocking || mAnimateKeyguardFadingOut) {
- // Wake and unlocking has a separate transition that must not be interfered with.
- mWakingUpFromAodStarting = false;
- mWakingUpFromAodInProgress = false;
- return;
- }
- if (mWakingUpFromAodStarting) {
- mWakingUpFromAodInProgress = true;
- mWakingUpFromAodStarting = false;
- mAnimateChange = true;
- scheduleUpdate();
- }
- }
-
- public void setWakeAndUnlocking() {
- mWakeAndUnlocking = true;
- mAnimatingDozeUnlock = true;
- mWakingUpFromAodStarting = false;
- mWakingUpFromAodInProgress = false;
- scheduleUpdate();
- }
-
- public void animateKeyguardFadingOut(long delay, long duration, Runnable onAnimationFinished,
- boolean skipFirstFrame) {
- mWakeAndUnlocking = false;
- mAnimateKeyguardFadingOut = true;
- mDurationOverride = duration;
- mAnimationDelay = delay;
- mAnimateChange = true;
- mSkipFirstFrame = skipFirstFrame;
- mOnAnimationFinished = onAnimationFinished;
-
- if (!mKeyguardUpdateMonitor.needsSlowUnlockTransition()) {
- scheduleUpdate();
-
- // No need to wait for the next frame to be drawn for this case - onPreDraw will execute
- // the changes we just scheduled.
- onPreDraw();
- } else {
-
- // In case the user isn't unlocked, make sure to delay a bit because the system is hosed
- // with too many things in this case, in order to not skip the initial frames.
- mScrimInFront.postOnAnimationDelayed(this::scheduleUpdate, 16);
- }
- }
-
- public void abortKeyguardFadingOut() {
- if (mAnimateKeyguardFadingOut) {
- endAnimateKeyguardFadingOut(true /* force */);
- }
- }
-
- public void animateKeyguardUnoccluding(long duration) {
- mAnimateChange = false;
- setScrimBehindAlpha(0f);
- mAnimateChange = true;
- scheduleUpdate();
- mDurationOverride = duration;
- }
-
- public void animateGoingToFullShade(long delay, long duration) {
- mDurationOverride = duration;
- mAnimationDelay = delay;
- mAnimateChange = true;
- scheduleUpdate();
- }
-
- public void setDozing(boolean dozing) {
- if (mDozing != dozing) {
- mDozing = dozing;
- scheduleUpdate();
- }
- }
-
- public void setDozeInFrontAlpha(float alpha) {
- mDozeInFrontAlpha = alpha;
- updateScrimColor(mScrimInFront);
- }
-
- public void setDozeBehindAlpha(float alpha) {
- mDozeBehindAlpha = alpha;
- updateScrimColor(mScrimBehind);
- }
-
- public float getDozeBehindAlpha() {
- return mDozeBehindAlpha;
- }
-
- public float getDozeInFrontAlpha() {
- return mDozeInFrontAlpha;
- }
-
+ /**
+ * Keyguard and shade scrim opacity varies according to how many notifications are visible.
+ * @param notificationCount Number of visible notifications.
+ */
public void setNotificationCount(int notificationCount) {
final float maxNotificationDensity = 3;
float notificationDensity = Math.min(notificationCount / maxNotificationDensity, 1f);
@@ -319,15 +335,11 @@
notificationDensity);
if (mScrimBehindAlphaKeyguard != newAlpha) {
mScrimBehindAlphaKeyguard = newAlpha;
- mAnimateChange = true;
- scheduleUpdate();
- }
- }
- private float getScrimInFrontAlpha() {
- return mKeyguardUpdateMonitor.needsSlowUnlockTransition()
- ? SCRIM_IN_FRONT_ALPHA_LOCKED
- : SCRIM_IN_FRONT_ALPHA;
+ if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER) {
+ scheduleUpdate();
+ }
+ }
}
/**
@@ -352,7 +364,7 @@
if (mNeedsDrawableColorUpdate) {
mNeedsDrawableColorUpdate = false;
final GradientColors currentScrimColors;
- if (mKeyguardShowing) {
+ if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER) {
// Always animate color changes if we're seeing the keyguard
mScrimInFront.setColors(mLockColors, true /* animated */);
mScrimBehind.setColors(mLockColors, true /* animated */);
@@ -375,77 +387,31 @@
mLightBarController.setScrimColor(mScrimInFront.getColors());
}
- if (mAnimateKeyguardFadingOut || mForceHideScrims) {
- setScrimInFrontAlpha(0f);
- setScrimBehindAlpha(0f);
- } else if (mWakeAndUnlocking) {
- // During wake and unlock, we first hide everything behind a black scrim, which then
- // gets faded out from animateKeyguardFadingOut. This must never be animated.
- mAnimateChange = false;
- if (mDozing) {
- setScrimInFrontAlpha(0f);
- setScrimBehindAlpha(1f);
- } else {
- setScrimInFrontAlpha(1f);
- setScrimBehindAlpha(0f);
- }
- } else if (!mKeyguardShowing && !mBouncerShowing && !mWakingUpFromAodStarting) {
- updateScrimNormal();
- setScrimInFrontAlpha(0);
- } else {
- updateScrimKeyguard();
- }
- mAnimateChange = false;
+ setScrimInFrontAlpha(mCurrentInFrontAlpha);
+ setScrimBehindAlpha(mCurrentBehindAlpha);
+
dispatchScrimsVisible();
}
private void dispatchScrimsVisible() {
boolean scrimsVisible = mScrimBehind.getViewAlpha() > 0 || mScrimInFront.getViewAlpha() > 0;
- if (mScrimsVisble != scrimsVisible) {
- mScrimsVisble = scrimsVisible;
+ if (mScrimsVisible != scrimsVisible) {
+ mScrimsVisible = scrimsVisible;
mScrimVisibleListener.accept(scrimsVisible);
}
}
- private void updateScrimKeyguard() {
- if (mTracking && mDarkenWhileDragging) {
- float behindFraction = Math.max(0, Math.min(mFraction, 1));
- float fraction = 1 - behindFraction;
- fraction = (float) Math.pow(fraction, 0.8f);
- behindFraction = (float) Math.pow(behindFraction, 0.8f);
- setScrimInFrontAlpha(fraction * getScrimInFrontAlpha());
- setScrimBehindAlpha(behindFraction * mScrimBehindAlphaKeyguard);
- } else if (mBouncerShowing && !mBouncerIsKeyguard) {
- setScrimInFrontAlpha(getScrimInFrontAlpha());
- updateScrimNormal();
- } else if (mBouncerShowing) {
- setScrimInFrontAlpha(0f);
- setScrimBehindAlpha(mScrimBehindAlpha);
- } else {
- float fraction = Math.max(0, Math.min(mFraction, 1));
- if (mWakingUpFromAodStarting) {
- setScrimInFrontAlpha(1f);
- } else {
- setScrimInFrontAlpha(0f);
- }
- setScrimBehindAlpha(fraction
- * (mScrimBehindAlphaKeyguard - mScrimBehindAlphaUnlocking)
- + mScrimBehindAlphaUnlocking);
- }
- }
-
- private void updateScrimNormal() {
+ private float getInterpolatedFraction() {
float frac = mFraction;
// let's start this 20% of the way down the screen
frac = frac * 1.2f - 0.2f;
if (frac <= 0) {
- setScrimBehindAlpha(0);
+ return 0;
} else {
// woo, special effects
- final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f))));
- setScrimBehindAlpha(k * mScrimBehindAlpha);
+ return (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f))));
}
}
@@ -455,102 +421,76 @@
private void setScrimInFrontAlpha(float alpha) {
setScrimAlpha(mScrimInFront, alpha);
- if (alpha == 0f) {
- mScrimInFront.setClickable(false);
- } else {
- // Eat touch events (unless dozing).
- mScrimInFront.setClickable(!mDozing);
- }
}
private void setScrimAlpha(View scrim, float alpha) {
- updateScrim(mAnimateChange, scrim, alpha, getCurrentScrimAlpha(scrim));
- }
-
- protected float getDozeAlpha(View scrim) {
- return scrim == mScrimBehind ? mDozeBehindAlpha : mDozeInFrontAlpha;
- }
-
- protected float getCurrentScrimAlpha(View scrim) {
- return scrim == mScrimBehind ? mCurrentBehindAlpha
- : scrim == mScrimInFront ? mCurrentInFrontAlpha
- : mCurrentHeadsUpAlpha;
- }
-
- private void setCurrentScrimAlpha(View scrim, float alpha) {
- if (scrim == mScrimBehind) {
- mCurrentBehindAlpha = alpha;
- mLightBarController.setScrimAlpha(mCurrentBehindAlpha);
- } else if (scrim == mScrimInFront) {
- mCurrentInFrontAlpha = alpha;
+ if (alpha == 0f) {
+ scrim.setClickable(false);
} else {
- alpha = Math.max(0.0f, Math.min(1.0f, alpha));
- mCurrentHeadsUpAlpha = alpha;
+ // Eat touch events (unless dozing).
+ scrim.setClickable(!(mState == ScrimState.AOD));
}
+ updateScrim(mAnimateChange, scrim, alpha);
}
- private void updateScrimColor(View scrim) {
- float alpha1 = getCurrentScrimAlpha(scrim);
+ private void updateScrimColor(View scrim, float alpha, int tint) {
+ alpha = Math.max(0, Math.min(1.0f, alpha));
if (scrim instanceof ScrimView) {
ScrimView scrimView = (ScrimView) scrim;
- float dozeAlpha = getDozeAlpha(scrim);
- float alpha = 1 - (1 - alpha1) * (1 - dozeAlpha);
- alpha = Math.max(0, Math.min(1.0f, alpha));
- scrimView.setViewAlpha(alpha);
Trace.traceCounter(Trace.TRACE_TAG_APP,
scrim == mScrimInFront ? "front_scrim_alpha" : "back_scrim_alpha",
(int) (alpha * 255));
- int dozeTint = Color.TRANSPARENT;
-
- boolean dozing = mAnimatingDozeUnlock || mDozing;
- boolean frontScrimDozing = mWakingUpFromAodInProgress;
- if (dozing || frontScrimDozing && scrim == mScrimInFront) {
- dozeTint = Color.BLACK;
- }
Trace.traceCounter(Trace.TRACE_TAG_APP,
scrim == mScrimInFront ? "front_scrim_tint" : "back_scrim_tint",
- dozeTint == Color.BLACK ? 1 : 0);
+ Color.alpha(tint));
- scrimView.setTint(dozeTint);
+ scrimView.setTint(tint);
+ scrimView.setViewAlpha(alpha);
} else {
- scrim.setAlpha(alpha1);
+ scrim.setAlpha(alpha);
}
dispatchScrimsVisible();
}
- private void startScrimAnimation(final View scrim, float target) {
- float current = getCurrentScrimAlpha(scrim);
- ValueAnimator anim = ValueAnimator.ofFloat(current, target);
+ private int getCurrentScrimTint(View scrim) {
+ return scrim == mScrimInFront ? mCurrentInFrontTint : mCurrentBehindTint;
+ }
+
+ private void startScrimAnimation(final View scrim, float current, float target) {
+ ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
+ final int initialScrimTint = scrim instanceof ScrimView ? ((ScrimView) scrim).getTint() :
+ Color.TRANSPARENT;
anim.addUpdateListener(animation -> {
- float alpha = (float) animation.getAnimatedValue();
- setCurrentScrimAlpha(scrim, alpha);
- updateScrimColor(scrim);
+ final float animAmount = (float) animation.getAnimatedValue();
+ final int finalScrimTint = scrim == mScrimInFront ?
+ mCurrentInFrontTint : mCurrentBehindTint;
+ float alpha = MathUtils.lerp(current, target, animAmount);
+ int tint = ColorUtils.blendARGB(initialScrimTint, finalScrimTint, animAmount);
+ updateScrimColor(scrim, alpha, tint);
dispatchScrimsVisible();
});
anim.setInterpolator(getInterpolator());
anim.setStartDelay(mAnimationDelay);
- anim.setDuration(mDurationOverride != -1 ? mDurationOverride : ANIMATION_DURATION);
+ anim.setDuration(mAnimationDuration);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
+ if (mKeyguardFadingOutInProgress) {
+ mKeyguardFadeoutAnimation = null;
+ mKeyguardFadingOutInProgress = false;
+ }
+ onFinished();
+
+ scrim.setTag(TAG_KEY_ANIM, null);
+ scrim.setTag(TAG_KEY_ANIM_TARGET, null);
+ dispatchScrimsVisible();
+
if (!mDeferFinishedListener && mOnAnimationFinished != null) {
mOnAnimationFinished.run();
mOnAnimationFinished = null;
}
- if (mKeyguardFadingOutInProgress) {
- mKeyguardFadeoutAnimation = null;
- mKeyguardFadingOutInProgress = false;
- mAnimatingDozeUnlock = false;
- }
- if (mWakingUpFromAodAnimationRunning && !mDeferFinishedListener) {
- mWakingUpFromAodAnimationRunning = false;
- mWakingUpFromAodInProgress = false;
- }
- scrim.setTag(TAG_KEY_ANIM, null);
- scrim.setTag(TAG_KEY_ANIM_TARGET, null);
- dispatchScrimsVisible();
}
});
anim.start();
@@ -558,12 +498,6 @@
mKeyguardFadingOutInProgress = true;
mKeyguardFadeoutAnimation = anim;
}
- if (mWakingUpFromAodInProgress) {
- mWakingUpFromAodAnimationRunning = true;
- }
- if (mSkipFirstFrame) {
- anim.setCurrentPlayTime(16);
- }
scrim.setTag(TAG_KEY_ANIM, anim);
scrim.setTag(TAG_KEY_ANIM_TARGET, target);
}
@@ -582,19 +516,33 @@
public boolean onPreDraw() {
mScrimBehind.getViewTreeObserver().removeOnPreDrawListener(this);
mUpdatePending = false;
- if (mDontAnimateBouncerChanges) {
- mDontAnimateBouncerChanges = false;
+ if (mCallback != null) {
+ mCallback.onStart();
}
updateScrims();
- mDurationOverride = -1;
- mAnimationDelay = 0;
- mSkipFirstFrame = false;
// Make sure that we always call the listener even if we didn't start an animation.
endAnimateKeyguardFadingOut(false /* force */);
return true;
}
+ private void onFinished() {
+ if (mWakeLockHeld) {
+ mWakeLock.release();
+ mWakeLockHeld = false;
+ }
+ if (mCallback != null) {
+ mCallback.onFinished();
+ mCallback = null;
+ }
+ // When unlocking with fingerprint, we'll fade the scrims from black to transparent.
+ // At the end of the animation we need to remove the tint.
+ if (mState == ScrimState.UNLOCKED) {
+ mCurrentInFrontTint = Color.TRANSPARENT;
+ mCurrentBehindTint = Color.TRANSPARENT;
+ }
+ }
+
private void endAnimateKeyguardFadingOut(boolean force) {
mAnimateKeyguardFadingOut = false;
if (force || (!isAnimating(mScrimInFront) && !isAnimating(mScrimBehind))) {
@@ -603,8 +551,6 @@
mOnAnimationFinished = null;
}
mKeyguardFadingOutInProgress = false;
- if (!mWakeAndUnlocking || force)
- mAnimatingDozeUnlock = false;
}
}
@@ -641,16 +587,19 @@
}
private void updateHeadsUpScrim(boolean animate) {
- updateScrim(animate, mHeadsUpScrim, calculateHeadsUpAlpha(), mCurrentHeadsUpAlpha);
+ updateScrim(animate, mHeadsUpScrim, calculateHeadsUpAlpha());
}
- private void updateScrim(boolean animate, View scrim, float alpha, float currentAlpha) {
- if (mKeyguardFadingOutInProgress && mKeyguardFadeoutAnimation.getCurrentPlayTime() != 0) {
- return;
- }
+ @VisibleForTesting
+ void setOnAnimationFinished(Runnable onAnimationFinished) {
+ mOnAnimationFinished = onAnimationFinished;
+ }
- ValueAnimator previousAnimator = ViewState.getChildTag(scrim,
- TAG_KEY_ANIM);
+ private void updateScrim(boolean animate, View scrim, float alpha) {
+ final float currentAlpha = scrim instanceof ScrimView ? ((ScrimView) scrim).getViewAlpha()
+ : scrim.getAlpha();
+
+ ValueAnimator previousAnimator = ViewState.getChildTag(scrim, TAG_KEY_ANIM);
float animEndValue = -1;
if (previousAnimator != null) {
if (animate || alpha == currentAlpha) {
@@ -664,9 +613,37 @@
animEndValue = ViewState.getChildTag(scrim, TAG_END_ALPHA);
}
}
- if (alpha != currentAlpha && alpha != animEndValue) {
+
+ final boolean blankingInProgress = mScrimInFront.getTag(TAG_KEY_ANIM_BLANK) != null;
+ if (mBlankScreen || blankingInProgress) {
+ if (!blankingInProgress) {
+ blankDisplay();
+ }
+ return;
+ } else if (!mScreenBlankingCallbackCalled) {
+ // Not blanking the screen. Letting the callback know that we're ready
+ // to replace what was on the screen before.
+ if (mCallback != null) {
+ mCallback.onDisplayBlanked();
+ mScreenBlankingCallbackCalled = true;
+ }
+ }
+
+ // TODO factor mLightBarController out of this class
+ if (scrim == mScrimBehind) {
+ mLightBarController.setScrimAlpha(alpha);
+ }
+
+ final ScrimView scrimView = scrim instanceof ScrimView ? (ScrimView) scrim : null;
+ final boolean wantsAlphaUpdate = alpha != currentAlpha && alpha != animEndValue;
+ final boolean wantsTintUpdate = scrimView != null
+ && scrimView.getTint() != getCurrentScrimTint(scrimView);
+
+ if (wantsAlphaUpdate || wantsTintUpdate) {
if (animate) {
- startScrimAnimation(scrim, alpha);
+ final float fromAlpha = scrimView == null ? scrim.getAlpha()
+ : scrimView.getViewAlpha();
+ startScrimAnimation(scrim, fromAlpha, alpha);
scrim.setTag(TAG_START_ALPHA, currentAlpha);
scrim.setTag(TAG_END_ALPHA, alpha);
} else {
@@ -685,13 +662,62 @@
previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
} else {
// update the alpha directly
- setCurrentScrimAlpha(scrim, alpha);
- updateScrimColor(scrim);
+ updateScrimColor(scrim, alpha, getCurrentScrimTint(scrim));
+ onFinished();
}
}
+ } else {
+ onFinished();
}
}
+ private void blankDisplay() {
+ final float initialAlpha = mScrimInFront.getViewAlpha();
+ final int initialTint = mScrimInFront.getTint();
+ ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
+ anim.addUpdateListener(animation -> {
+ final float amount = (float) animation.getAnimatedValue();
+ float animAlpha = MathUtils.lerp(initialAlpha, 1, amount);
+ int animTint = ColorUtils.blendARGB(initialTint, Color.BLACK, amount);
+ updateScrimColor(mScrimInFront, animAlpha, animTint);
+ dispatchScrimsVisible();
+ });
+ anim.setInterpolator(getInterpolator());
+ anim.setDuration(mDozeParameters.getPulseInDuration());
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mCallback != null) {
+ mCallback.onDisplayBlanked();
+ mScreenBlankingCallbackCalled = true;
+ }
+ Runnable blankingCallback = () -> {
+ mScrimInFront.setTag(TAG_KEY_ANIM_BLANK, null);
+ mBlankScreen = false;
+ // Try again.
+ updateScrims();
+ };
+
+ // Setting power states can happen after we push out the frame. Make sure we
+ // stay fully opaque until the power state request reaches the lower levels.
+ getHandler().postDelayed(blankingCallback, 100);
+
+ }
+ });
+ anim.start();
+ mScrimInFront.setTag(TAG_KEY_ANIM_BLANK, anim);
+
+ // Finish animation if we're already at its final state
+ if (initialAlpha == 1 && mScrimInFront.getTint() == Color.BLACK) {
+ anim.end();
+ }
+ }
+
+ @VisibleForTesting
+ protected Handler getHandler() {
+ return Handler.getMain();
+ }
+
/**
* Set the amount the current top heads up view is dragged. The range is from 0 to 1 and 0 means
* the heads up is in its resting space and 1 means it's fully dragged out.
@@ -719,23 +745,13 @@
return alpha * expandFactor;
}
- public void forceHideScrims(boolean hide, boolean animated) {
- mForceHideScrims = hide;
- mAnimateChange = animated;
- scheduleUpdate();
- }
-
- public void dontAnimateBouncerChangesUntilNextFrame() {
- mDontAnimateBouncerChanges = true;
- }
-
public void setExcludedBackgroundArea(Rect area) {
mScrimBehind.setExcludedArea(area);
}
public int getBackgroundColor() {
int color = mLockColors.getMainColor();
- return Color.argb((int) (mScrimBehind.getAlpha() * Color.alpha(color)),
+ return Color.argb((int) (mScrimBehind.getViewAlpha() * Color.alpha(color)),
Color.red(color), Color.green(color), Color.blue(color));
}
@@ -764,27 +780,41 @@
}
if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
- ColorExtractor.TYPE_DARK, mKeyguardShowing);
+ ColorExtractor.TYPE_DARK, mState != ScrimState.UNLOCKED);
mNeedsDrawableColorUpdate = true;
scheduleUpdate();
}
}
- public void dump(PrintWriter pw) {
- pw.println(" ScrimController:");
+ @VisibleForTesting
+ protected WakeLock createWakeLock() {
+ return new DelayedWakeLock(getHandler(),
+ WakeLock.createPartial(mContext, "Doze"));
+ }
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println(" ScrimController:");
+ pw.print(" state:"); pw.println(mState);
pw.print(" frontScrim:"); pw.print(" viewAlpha="); pw.print(mScrimInFront.getViewAlpha());
pw.print(" alpha="); pw.print(mCurrentInFrontAlpha);
- pw.print(" dozeAlpha="); pw.print(mDozeInFrontAlpha);
pw.print(" tint=0x"); pw.println(Integer.toHexString(mScrimInFront.getTint()));
pw.print(" backScrim:"); pw.print(" viewAlpha="); pw.print(mScrimBehind.getViewAlpha());
pw.print(" alpha="); pw.print(mCurrentBehindAlpha);
- pw.print(" dozeAlpha="); pw.print(mDozeBehindAlpha);
pw.print(" tint=0x"); pw.println(Integer.toHexString(mScrimBehind.getTint()));
- pw.print(" mBouncerShowing="); pw.println(mBouncerShowing);
pw.print(" mTracking="); pw.println(mTracking);
- pw.print(" mForceHideScrims="); pw.println(mForceHideScrims);
+ }
+
+ public interface Callback {
+ default void onStart() {
+ }
+ default void onDisplayBlanked() {
+ }
+ default void onFinished() {
+ }
+ default void onCancelled() {
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
new file mode 100644
index 0000000..0db98f3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.graphics.Color;
+import android.os.Trace;
+
+import com.android.systemui.statusbar.ScrimView;
+
+/**
+ * Possible states of the ScrimController state machine.
+ */
+public enum ScrimState {
+
+ /**
+ * Initial state.
+ */
+ UNINITIALIZED,
+
+ /**
+ * On the lock screen.
+ */
+ KEYGUARD {
+
+ @Override
+ public void prepare(ScrimState previousState) {
+ // DisplayPowerManager will blank the screen, we'll just
+ // set our scrim to black in this frame to avoid flickering and
+ // fade it out afterwards.
+ mBlankScreen = previousState == ScrimState.AOD;
+ if (previousState == ScrimState.AOD) {
+ updateScrimColor(mScrimInFront, 1, Color.BLACK);
+ }
+ mCurrentBehindAlpha = mScrimBehindAlphaKeyguard;
+ mCurrentInFrontAlpha = 0;
+ }
+ },
+
+ /**
+ * Showing password challenge.
+ */
+ BOUNCER {
+ @Override
+ public void prepare(ScrimState previousState) {
+ mCurrentBehindAlpha = ScrimController.SCRIM_BEHIND_ALPHA_UNLOCKING;
+ mCurrentInFrontAlpha = ScrimController.SCRIM_IN_FRONT_ALPHA_LOCKED;
+ }
+ },
+
+ /**
+ * Changing screen brightness from quick settings.
+ */
+ BRIGHTNESS_MIRROR {
+ @Override
+ public void prepare(ScrimState previousState) {
+ mCurrentBehindAlpha = 0;
+ mCurrentInFrontAlpha = 0;
+ }
+ },
+
+ /**
+ * Always on display or screen off.
+ */
+ AOD {
+ @Override
+ public void prepare(ScrimState previousState) {
+ if (previousState == ScrimState.PULSING) {
+ updateScrimColor(mScrimInFront, 1, Color.BLACK);
+ }
+ final boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn();
+ mBlankScreen = previousState == ScrimState.PULSING;
+ mCurrentBehindAlpha = 1;
+ mCurrentInFrontAlpha = alwaysOnEnabled ? mAodFrontScrimAlpha : 1f;
+ mCurrentInFrontTint = Color.BLACK;
+ mCurrentBehindTint = Color.BLACK;
+ // DisplayPowerManager will blank the screen for us, we just need
+ // to set our state.
+ mAnimateChange = false;
+ }
+ },
+
+ /**
+ * When phone wakes up because you received a notification.
+ */
+ PULSING {
+ @Override
+ public void prepare(ScrimState previousState) {
+ mCurrentBehindAlpha = 1;
+ mCurrentInFrontAlpha = 0;
+ mCurrentInFrontTint = Color.BLACK;
+ mCurrentBehindTint = Color.BLACK;
+ mBlankScreen = true;
+ updateScrimColor(mScrimInFront, 1, Color.BLACK);
+ }
+ },
+
+ /**
+ * Unlocked on top of an app (launcher or any other activity.)
+ */
+ UNLOCKED {
+ @Override
+ public void prepare(ScrimState previousState) {
+ mCurrentBehindAlpha = 0;
+ mCurrentInFrontAlpha = 0;
+ mAnimationDuration = StatusBar.FADE_KEYGUARD_DURATION;
+
+ if (previousState == ScrimState.AOD) {
+ // Fade from black to transparent when coming directly from AOD
+ updateScrimColor(mScrimInFront, 1, Color.BLACK);
+ updateScrimColor(mScrimBehind, 1, Color.BLACK);
+ // Scrims should still be black at the end of the transition.
+ mCurrentInFrontTint = Color.BLACK;
+ mCurrentBehindTint = Color.BLACK;
+ mBlankScreen = true;
+ } else {
+ // Scrims should still be black at the end of the transition.
+ mCurrentInFrontTint = Color.TRANSPARENT;
+ mCurrentBehindTint = Color.TRANSPARENT;
+ mBlankScreen = false;
+ }
+ }
+ };
+
+ boolean mBlankScreen = false;
+ long mAnimationDuration = ScrimController.ANIMATION_DURATION;
+ int mCurrentInFrontTint = Color.TRANSPARENT;
+ int mCurrentBehindTint = Color.TRANSPARENT;
+ boolean mAnimateChange = true;
+ float mCurrentInFrontAlpha;
+ float mCurrentBehindAlpha;
+ float mAodFrontScrimAlpha;
+ float mScrimBehindAlphaKeyguard;
+ ScrimView mScrimInFront;
+ ScrimView mScrimBehind;
+ DozeParameters mDozeParameters;
+
+ public void init(ScrimView scrimInFront, ScrimView scrimBehind, DozeParameters dozeParameters) {
+ mScrimInFront = scrimInFront;
+ mScrimBehind = scrimBehind;
+ mDozeParameters = dozeParameters;
+ }
+
+ public void prepare(ScrimState previousState) {
+ }
+
+ public float getFrontAlpha() {
+ return mCurrentInFrontAlpha;
+ }
+
+ public float getBehindAlpha() {
+ return mCurrentBehindAlpha;
+ }
+
+ public int getFrontTint() {
+ return mCurrentInFrontTint;
+ }
+
+ public int getBehindTint() {
+ return mCurrentBehindTint;
+ }
+
+ public long getAnimationDuration() {
+ return mAnimationDuration;
+ }
+
+ public boolean getBlanksScreen() {
+ return mBlankScreen;
+ }
+
+ public void updateScrimColor(ScrimView scrim, float alpha, int tint) {
+ Trace.traceCounter(Trace.TRACE_TAG_APP,
+ scrim == mScrimInFront ? "front_scrim_alpha" : "back_scrim_alpha",
+ (int) (alpha * 255));
+
+ Trace.traceCounter(Trace.TRACE_TAG_APP,
+ scrim == mScrimInFront ? "front_scrim_tint" : "back_scrim_tint",
+ Color.alpha(tint));
+
+ scrim.setTint(tint);
+ scrim.setViewAlpha(alpha);
+ }
+
+ public boolean getAnimateChange() {
+ return mAnimateChange;
+ }
+
+ public void setAodFrontScrimAlpha(float aodFrontScrimAlpha) {
+ mAodFrontScrimAlpha = aodFrontScrimAlpha;
+ }
+
+ public void setScrimBehindAlphaKeyguard(float scrimBehindAlphaKeyguard) {
+ mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 43cc0f7..80bab72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.phone;
-import static android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE;
import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.windowStateToString;
@@ -25,6 +24,9 @@
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
+import static com.android.systemui.statusbar.NotificationLockscreenUserManager
+ .NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION;
+import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
import static com.android.systemui.statusbar.NotificationMediaManager.DEBUG_MEDIA;
import static com.android.systemui.statusbar.notification.NotificationInflater.InflationCallback;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
@@ -108,7 +110,6 @@
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.SparseBooleanArray;
import android.view.Display;
import android.view.IWindowManager;
import android.view.KeyEvent;
@@ -127,7 +128,6 @@
import android.widget.ImageView;
import android.widget.RemoteViews;
import android.widget.TextView;
-import android.widget.Toast;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
@@ -153,7 +153,6 @@
import com.android.systemui.EventLogTags;
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.Interpolators;
-import com.android.systemui.OverviewProxyService;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
@@ -201,6 +200,8 @@
import com.android.systemui.statusbar.NotificationData.Entry;
import com.android.systemui.statusbar.NotificationGutsManager;
import com.android.systemui.statusbar.NotificationInfo;
+import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationShelf;
@@ -249,6 +250,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.Stack;
public class StatusBar extends SystemUI implements DemoMode,
@@ -266,7 +268,6 @@
= SystemProperties.getBoolean("debug.child_notifs", true);
public static final boolean FORCE_REMOTE_INPUT_HISTORY =
SystemProperties.getBoolean("debug.force_remoteinput_history", true);
- private static final boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false;
protected static final int MSG_HIDE_RECENT_APPS = 1020;
protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
@@ -277,7 +278,6 @@
protected static final boolean ENABLE_HEADS_UP = true;
protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
- private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
// Should match the values in PhoneWindowManager
public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
@@ -288,8 +288,6 @@
"com.android.systemui.statusbar.banner_action_cancel";
private static final String BANNER_ACTION_SETUP =
"com.android.systemui.statusbar.banner_action_setup";
- private static final String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
- = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
public static final String TAG = "StatusBar";
public static final boolean DEBUG = false;
public static final boolean SPEW = false;
@@ -379,13 +377,12 @@
*/
protected int mState;
protected boolean mBouncerShowing;
- protected boolean mShowLockscreenNotifications;
- protected boolean mAllowLockscreenRemoteInput;
private PhoneStatusBarPolicy mIconPolicy;
private VolumeComponent mVolumeComponent;
private BrightnessMirrorController mBrightnessMirrorController;
+ private boolean mBrightnessMirrorVisible;
protected FingerprintUnlockController mFingerprintUnlockController;
private LightBarController mLightBarController;
protected LockscreenWallpaper mLockscreenWallpaper;
@@ -542,6 +539,7 @@
new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
private NotificationMediaManager mMediaManager;
+ protected NotificationLockscreenUserManager mLockscreenUserManager;
/** Keys of notifications currently visible to the user. */
private final ArraySet<NotificationVisibility> mCurrentlyVisibleNotifications =
@@ -646,6 +644,28 @@
}
};
+ // Notifies StatusBarKeyguardViewManager every time the keyguard transition is over,
+ // this animation is tied to the scrim for historic reasons.
+ // TODO: notify when keyguard has faded away instead of the scrim.
+ private final ScrimController.Callback mUnlockScrimCallback = new ScrimController
+ .Callback() {
+ @Override
+ public void onFinished() {
+ if (mStatusBarKeyguardViewManager == null) {
+ Log.w(TAG, "Tried to notify keyguard visibility when "
+ + "mStatusBarKeyguardViewManager was null");
+ return;
+ }
+ mStatusBarKeyguardViewManager.onKeyguardFadedAway();
+ }
+
+ @Override
+ public void onCancelled() {
+ // Transition was cancelled because another one took over.
+ // Nothing to do in here but wait.
+ }
+ };
+
private NotificationMessagingUtil mMessagingUtil;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
private UserSwitcherController mUserSwitcherController;
@@ -715,6 +735,8 @@
mSystemServicesProxy = SystemServicesProxy.getInstance(mContext);
mOverlayManager = IOverlayManager.Stub.asInterface(
ServiceManager.getService(Context.OVERLAY_SERVICE));
+ mLockscreenUserManager = Dependency.get(NotificationLockscreenUserManager.class);
+ mGutsManager = Dependency.get(NotificationGutsManager.class);
mColorExtractor = Dependency.get(SysuiColorExtractor.class);
mColorExtractor.addOnColorsChangedListener(this);
@@ -750,26 +772,6 @@
mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
- mContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
- mSettingsObserver);
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
- mLockscreenSettingsObserver,
- UserHandle.USER_ALL);
- if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT),
- false,
- mSettingsObserver,
- UserHandle.USER_ALL);
- }
-
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
- true,
- mLockscreenSettingsObserver,
- UserHandle.USER_ALL);
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
@@ -781,6 +783,7 @@
mLockPatternUtils = new LockPatternUtils(mContext);
mMediaManager = new NotificationMediaManager(this, mContext);
+ mLockscreenUserManager.setUpWithPresenter(this);
// Connect in to the status bar manager service
mCommandQueue = getComponent(CommandQueue.class);
@@ -801,7 +804,6 @@
createAndAddWindows();
- mSettingsObserver.onChange(false); // set up
mCommandQueue.disable(switches[0], switches[6], false /* animate */);
setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
fullscreenStackBounds, dockedStackBounds);
@@ -816,14 +818,8 @@
}
// Set up the initial notification state.
- try {
- mNotificationListener.registerAsSystemService(mContext,
- new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
- UserHandle.USER_ALL);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to register notification listener", e);
- }
-
+ mNotificationListener = new NotificationListener(this, mContext);
+ mNotificationListener.register();
if (DEBUG) {
Log.d(TAG, String.format(
@@ -836,29 +832,13 @@
));
}
- mCurrentUserId = ActivityManager.getCurrentUser();
- setHeadsUpUser(mCurrentUserId);
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_SWITCHED);
- filter.addAction(Intent.ACTION_USER_ADDED);
- filter.addAction(Intent.ACTION_USER_PRESENT);
- filter.addAction(Intent.ACTION_USER_UNLOCKED);
- mContext.registerReceiver(mBaseBroadcastReceiver, filter);
+ setHeadsUpUser(mLockscreenUserManager.getCurrentUserId());
IntentFilter internalFilter = new IntentFilter();
- internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
internalFilter.addAction(BANNER_ACTION_CANCEL);
internalFilter.addAction(BANNER_ACTION_SETUP);
- mContext.registerReceiver(mBaseBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
-
- IntentFilter allUsersFilter = new IntentFilter();
- allUsersFilter.addAction(
- DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
- allUsersFilter.addAction(Intent.ACTION_DEVICE_LOCKED_CHANGED);
- mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
- null, null);
- updateCurrentProfilesCache();
+ mContext.registerReceiver(mBannerActionBroadcastReceiver, internalFilter, PERMISSION_SELF,
+ null);
IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
Context.VR_SERVICE));
@@ -872,7 +852,6 @@
// Lastly, call to the icon policy to install/update all the icons.
mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);
- mSettingsObserver.onChange(false); // set up
mHeadsUpObserver.onChange(true); // set up
if (ENABLE_HEADS_UP) {
@@ -917,8 +896,7 @@
// into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel);
mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller);
- mGutsManager = new NotificationGutsManager(this, mStackScroller,
- mCheckSaveListener, mContext,
+ mGutsManager.setUp(this, mStackScroller, mCheckSaveListener,
key -> {
try {
mBarService.onNotificationSettingsViewed(key);
@@ -1045,7 +1023,7 @@
if (mStatusBarWindowManager != null) {
mStatusBarWindowManager.setScrimsVisible(scrimsVisible);
}
- });
+ }, new DozeParameters(mContext));
if (mScrimSrcModeEnabled) {
Runnable runnable = () -> {
boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE;
@@ -1081,7 +1059,10 @@
final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
mIconController);
mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow,
- mScrimController);
+ (visible) -> {
+ mBrightnessMirrorVisible = visible;
+ updateScrimController();
+ });
fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> {
QS qs = (QS) f;
if (qs instanceof QSFragment) {
@@ -1401,7 +1382,7 @@
}
}
try {
- mBarService.onClearAllNotifications(mCurrentUserId);
+ mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId());
} catch (Exception ex) {
}
});
@@ -1441,15 +1422,6 @@
}
}
- protected void setZenMode(int mode) {
- // start old BaseStatusBar.setZenMode().
- if (isDeviceProvisioned()) {
- mZenMode = mode;
- updateNotifications();
- }
- // end old BaseStatusBar.setZenMode().
- }
-
protected void startKeyguard() {
Trace.beginSection("StatusBar#startKeyguard");
KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
@@ -1457,8 +1429,7 @@
mDozeScrimController, keyguardViewMediator,
mScrimController, this, UnlockMethodCache.getInstance(mContext));
mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
- getBouncerContainer(), mScrimController,
- mFingerprintUnlockController);
+ getBouncerContainer(), mFingerprintUnlockController);
mKeyguardIndicationController
.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
@@ -1541,13 +1512,19 @@
SystemServicesProxy.getInstance(mContext).awakenDreamsAsync();
}
- public void addNotification(StatusBarNotification notification, RankingMap ranking)
- throws InflationException {
+ @Override
+ public void addNotification(StatusBarNotification notification, RankingMap ranking) {
String key = notification.getKey();
if (DEBUG) Log.d(TAG, "addNotification key=" + key);
mNotificationData.updateRanking(ranking);
- Entry shadeEntry = createNotificationViews(notification);
+ Entry shadeEntry = null;
+ try {
+ shadeEntry = createNotificationViews(notification);
+ } catch (InflationException e) {
+ handleInflationException(notification, e);
+ return;
+ }
boolean isHeadsUped = shouldPeek(shadeEntry);
if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
if (shouldSuppressFullScreenIntent(key)) {
@@ -1561,11 +1538,11 @@
+ key);
}
} else {
- // Stop screensaver if the notification has a full-screen intent.
+ // Stop screensaver if the notification has a fullscreen intent.
// (like an incoming phone call)
awakenDreams();
- // not immersive & a full-screen alert should be shown
+ // not immersive & a fullscreen alert should be shown
if (DEBUG)
Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
try {
@@ -1642,7 +1619,8 @@
}
}
- protected void updateNotificationRanking(RankingMap ranking) {
+ @Override
+ public void updateNotificationRanking(RankingMap ranking) {
mNotificationData.updateRanking(ranking);
updateNotifications();
}
@@ -1695,7 +1673,7 @@
newNotification, sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
boolean updated = false;
try {
- updateNotification(newSbn, null);
+ updateNotificationInternal(newSbn, null);
updated = true;
} catch (InflationException e) {
deferRemoval = false;
@@ -1847,12 +1825,17 @@
int userId = ent.notification.getUserId();
// Display public version of the notification if we need to redact.
- boolean devicePublic = isLockscreenPublicMode(mCurrentUserId);
- boolean userPublic = devicePublic || isLockscreenPublicMode(userId);
- boolean needsRedaction = needsRedaction(ent);
+ // TODO: This area uses a lot of calls into NotificationLockscreenUserManager.
+ // We can probably move some of this code there.
+ boolean devicePublic = mLockscreenUserManager.isLockscreenPublicMode(
+ mLockscreenUserManager.getCurrentUserId());
+ boolean userPublic = devicePublic
+ || mLockscreenUserManager.isLockscreenPublicMode(userId);
+ boolean needsRedaction = mLockscreenUserManager.needsRedaction(ent);
boolean sensitive = userPublic && needsRedaction;
boolean deviceSensitive = devicePublic
- && !userAllowsPrivateNotificationsInPublic(mCurrentUserId);
+ && !mLockscreenUserManager.userAllowsPrivateNotificationsInPublic(
+ mLockscreenUserManager.getCurrentUserId());
ent.row.setSensitive(sensitive, deviceSensitive);
ent.row.setNeedsRedaction(needsRedaction);
if (mGroupManager.isChildInGroupWithSummary(ent.row.getStatusBarNotification())) {
@@ -1944,21 +1927,6 @@
mNotificationIconAreaController.updateNotificationIcons(mNotificationData);
}
- /** @return true if the entry needs redaction when on the lockscreen. */
- private boolean needsRedaction(Entry ent) {
- int userId = ent.notification.getUserId();
-
- boolean currentUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(mCurrentUserId);
- boolean notiUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(userId);
- boolean redactedLockscreen = currentUserWantsRedaction || notiUserWantsRedaction;
-
- boolean notificationRequestsRedaction =
- ent.notification.getNotification().visibility == Notification.VISIBILITY_PRIVATE;
- boolean userForcesRedaction = packageHasVisibilityOverride(ent.notification.getKey());
-
- return userForcesRedaction || notificationRequestsRedaction && redactedLockscreen;
- }
-
/**
* Disable QS if device not provisioned.
* If the user switcher is simple then disable QS during setup because
@@ -2061,9 +2029,6 @@
mQSPanel.clickTile(tile);
}
- private boolean packageHasVisibilityOverride(String key) {
- return mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_PRIVATE;
- }
private void updateClearAll() {
if (!mClearAllEnabled) {
@@ -2640,7 +2605,7 @@
}
public boolean isPulsing() {
- return mDozeScrimController.isPulsing();
+ return mDozeScrimController != null && mDozeScrimController.isPulsing();
}
@Override
@@ -2665,7 +2630,7 @@
OverlayInfo themeInfo = null;
try {
themeInfo = mOverlayManager.getOverlayInfo("com.android.systemui.theme.dark",
- mCurrentUserId);
+ mLockscreenUserManager.getCurrentUserId());
} catch (RemoteException e) {
e.printStackTrace();
}
@@ -3304,13 +3269,11 @@
pw.println(BarTransitions.modeToString(mStatusBarMode));
pw.print(" mDozing="); pw.println(mDozing);
pw.print(" mZenMode=");
- pw.println(Settings.Global.zenModeToString(mZenMode));
+ pw.println(Settings.Global.zenModeToString(Settings.Global.getInt(
+ mContext.getContentResolver(), Settings.Global.ZEN_MODE,
+ Settings.Global.ZEN_MODE_OFF)));
pw.print(" mUseHeadsUp=");
pw.println(mUseHeadsUp);
- pw.print(" mGutsManager: ");
- if (mGutsManager != null) {
- mGutsManager.dump(fd, pw, args);
- }
if (mStatusBarView != null) {
dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
}
@@ -3348,7 +3311,7 @@
}
if (mScrimController != null) {
- mScrimController.dump(pw);
+ mScrimController.dump(fd, pw, args);
}
if (DUMPTRUCK) {
@@ -3413,7 +3376,19 @@
private void addStatusBarWindow() {
makeStatusBarView();
mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
- mRemoteInputController = new RemoteInputController(mHeadsUpManager);
+ mRemoteInputController = new RemoteInputController(new RemoteInputController.Delegate() {
+ public void setRemoteInputActive(NotificationData.Entry entry,
+ boolean remoteInputActive) {
+ mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);
+ }
+ public void lockScrollTo(NotificationData.Entry entry) {
+ mStackScroller.lockScrollTo(entry.row);
+ }
+ public void requestDisallowLongPressAndDismiss() {
+ mStackScroller.requestDisallowLongPress();
+ mStackScroller.requestDisallowDismiss();
+ }
+ });
mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
}
@@ -3443,7 +3418,7 @@
if (onlyProvisioned && !isDeviceProvisioned()) return;
final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
- mContext, intent, mCurrentUserId);
+ mContext, intent, mLockscreenUserManager.getCurrentUserId());
Runnable runnable = () -> {
mAssistManager.hideAssist();
intent.setFlags(
@@ -3535,7 +3510,7 @@
if (mRemoteInputController != null) {
mRemoteInputController.closeRemoteInputs();
}
- if (isCurrentProfile(getSendingUserId())) {
+ if (mLockscreenUserManager.isCurrentProfile(getSendingUserId())) {
int flags = CommandQueue.FLAG_EXCLUDE_NONE;
String reason = intent.getStringExtra("reason");
if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
@@ -3627,7 +3602,8 @@
mScreenPinningRequest.onConfigurationChanged();
}
- public void userSwitched(int newUserId) {
+ @Override
+ public void onUserSwitched(int newUserId) {
// Begin old BaseStatusBar.userSwitched
setHeadsUpUser(newUserId);
// End old BaseStatusBar.userSwitched
@@ -3644,6 +3620,11 @@
setLockscreenUser(newUserId);
}
+ @Override
+ public NotificationLockscreenUserManager getNotificationLockscreenUserManager() {
+ return mLockscreenUserManager;
+ }
+
protected void setLockscreenUser(int newUserId) {
mLockscreenWallpaper.setCurrentUser(newUserId);
mScrimController.setCurrentUser(newUserId);
@@ -3716,23 +3697,35 @@
* See also StatusBar.setPanelExpanded for another place where we attempt to do this.
*/
private void handleVisibleToUserChangedImpl(boolean visibleToUser) {
- try {
- if (visibleToUser) {
- boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
- boolean clearNotificationEffects =
- !isPresenterFullyCollapsed() &&
- (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED);
- int notificationLoad = mNotificationData.getActiveNotifications().size();
- if (pinnedHeadsUp && isPresenterFullyCollapsed()) {
- notificationLoad = 1;
- }
- mBarService.onPanelRevealed(clearNotificationEffects, notificationLoad);
- } else {
- mBarService.onPanelHidden();
+ if (visibleToUser) {
+ boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
+ boolean clearNotificationEffects =
+ !isPresenterFullyCollapsed() &&
+ (mState == StatusBarState.SHADE
+ || mState == StatusBarState.SHADE_LOCKED);
+ int notificationLoad = mNotificationData.getActiveNotifications().size();
+ if (pinnedHeadsUp && isPresenterFullyCollapsed()) {
+ notificationLoad = 1;
}
- } catch (RemoteException ex) {
- // Won't fail unless the world has ended.
+ final int finalNotificationLoad = notificationLoad;
+ mUiOffloadThread.submit(() -> {
+ try {
+ mBarService.onPanelRevealed(clearNotificationEffects,
+ finalNotificationLoad);
+ } catch (RemoteException ex) {
+ // Won't fail unless the world has ended.
+ }
+ });
+ } else {
+ mUiOffloadThread.submit(() -> {
+ try {
+ mBarService.onPanelHidden();
+ } catch (RemoteException ex) {
+ // Won't fail unless the world has ended.
+ }
+ });
}
+
}
private void stopNotificationLogging() {
@@ -3768,21 +3761,23 @@
newlyVisible.toArray(new NotificationVisibility[newlyVisible.size()]);
NotificationVisibility[] noLongerVisibleAr =
noLongerVisible.toArray(new NotificationVisibility[noLongerVisible.size()]);
- try {
- mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr);
- } catch (RemoteException e) {
- // Ignore.
- }
-
- final int N = newlyVisible.size();
- if (N > 0) {
- String[] newlyVisibleKeyAr = new String[N];
- for (int i = 0; i < N; i++) {
- newlyVisibleKeyAr[i] = newlyVisibleAr[i].key;
+ mUiOffloadThread.submit(() -> {
+ try {
+ mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr);
+ } catch (RemoteException e) {
+ // Ignore.
}
- setNotificationsShown(newlyVisibleKeyAr);
- }
+ final int N = newlyVisible.size();
+ if (N > 0) {
+ String[] newlyVisibleKeyAr = new String[N];
+ for (int i = 0; i < N; i++) {
+ newlyVisibleKeyAr[i] = newlyVisibleAr[i].key;
+ }
+
+ setNotificationsShown(newlyVisibleKeyAr);
+ }
+ });
}
// State logging
@@ -3890,7 +3885,8 @@
public void destroy() {
// Begin old BaseStatusBar.destroy().
- mContext.unregisterReceiver(mBaseBroadcastReceiver);
+ mContext.unregisterReceiver(mBannerActionBroadcastReceiver);
+ mLockscreenUserManager.destroy();
try {
mNotificationListener.unregisterAsSystemService();
} catch (RemoteException e) {
@@ -4081,7 +4077,6 @@
releaseGestureWakeLock();
runLaunchTransitionEndRunnable();
mLaunchTransitionFadingAway = false;
- mScrimController.forceHideScrims(false /* hide */, false /* animated */);
updateMediaMetaData(true /* metaDataChanged */, true);
}
@@ -4114,7 +4109,7 @@
if (beforeFading != null) {
beforeFading.run();
}
- mScrimController.forceHideScrims(true /* hide */, false /* animated */);
+ updateScrimController();
updateMediaMetaData(false, true);
mNotificationPanel.setAlpha(1);
mStackScroller.setParentNotFullyVisible(true);
@@ -4145,6 +4140,13 @@
.setStartDelay(0)
.setDuration(FADE_KEYGUARD_DURATION_PULSING)
.setInterpolator(ScrimController.KEYGUARD_FADE_OUT_INTERPOLATOR)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ hideKeyguard();
+ mStatusBarKeyguardViewManager.onKeyguardFadedAway();
+ }
+ })
.start();
}
@@ -4152,7 +4154,6 @@
* Plays the animation when an activity that was occluding Keyguard goes away.
*/
public void animateKeyguardUnoccluding() {
- mScrimController.animateKeyguardUnoccluding(500);
mNotificationPanel.setExpandedFraction(0f);
animateExpandNotificationsPanel();
}
@@ -4291,18 +4292,21 @@
mKeyguardMonitor.notifyKeyguardDoneFading();
}
+ // TODO: Move this to NotificationLockscreenUserManager.
private void updatePublicMode() {
final boolean showingKeyguard = mStatusBarKeyguardViewManager.isShowing();
final boolean devicePublic = showingKeyguard
- && mStatusBarKeyguardViewManager.isSecure(mCurrentUserId);
+ && mStatusBarKeyguardViewManager.isSecure(
+ mLockscreenUserManager.getCurrentUserId());
// Look for public mode users. Users are considered public in either case of:
// - device keyguard is shown in secure mode;
// - profile is locked with a work challenge.
- for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
- final int userId = mCurrentProfiles.valueAt(i).id;
+ SparseArray<UserInfo> currentProfiles = mLockscreenUserManager.getCurrentProfiles();
+ for (int i = currentProfiles.size() - 1; i >= 0; i--) {
+ final int userId = currentProfiles.valueAt(i).id;
boolean isProfilePublic = devicePublic;
- if (!devicePublic && userId != mCurrentUserId) {
+ if (!devicePublic && userId != mLockscreenUserManager.getCurrentUserId()) {
// We can't rely on KeyguardManager#isDeviceLocked() for unified profile challenge
// due to a race condition where this code could be called before
// TrustManagerService updates its internal records, resulting in an incorrect
@@ -4312,7 +4316,7 @@
isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
}
}
- setLockscreenPublicMode(isProfilePublic, userId);
+ mLockscreenUserManager.setLockscreenPublicMode(isProfilePublic, userId);
}
}
@@ -4340,11 +4344,6 @@
mAmbientIndicationContainer.setVisibility(View.INVISIBLE);
}
}
- if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
- mScrimController.setKeyguardShowing(true);
- } else {
- mScrimController.setKeyguardShowing(false);
- }
mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade);
updateTheme();
updateDozingState();
@@ -4352,6 +4351,7 @@
updateStackScrollerState(goingToFullShade, fromShadeLocked);
updateNotifications();
checkBarModes();
+ updateScrimController();
updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
mUnlockMethodCache.isMethodSecure(),
@@ -4374,7 +4374,7 @@
mUiOffloadThread.submit(() -> {
try {
mOverlayManager.setEnabled("com.android.systemui.theme.dark",
- useDarkTheme, mCurrentUserId);
+ useDarkTheme, mLockscreenUserManager.getCurrentUserId());
} catch (RemoteException e) {
Log.w(TAG, "Can't change theme", e);
}
@@ -4415,11 +4415,10 @@
boolean animate = !mDozing && mDozeServiceHost.shouldAnimateWakeup();
mNotificationPanel.setDozing(mDozing, animate);
mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation);
- mScrimController.setDozing(mDozing);
+ mDozeScrimController.setDozing(mDozing);
mKeyguardIndicationController.setDozing(mDozing);
mNotificationPanel.setDark(mDozing, animate);
updateQsExpansionEnabled();
- mDozeScrimController.setDozing(mDozing, animate);
updateRowStates();
Trace.endSection();
}
@@ -4427,7 +4426,7 @@
public void updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked) {
if (mStackScroller == null) return;
boolean onKeyguard = mState == StatusBarState.KEYGUARD;
- boolean publicMode = isAnyProfilePublicMode();
+ boolean publicMode = mLockscreenUserManager.isAnyProfilePublicMode();
mStackScroller.setHideSensitive(publicMode, goingToFullShade);
mStackScroller.setDimmed(onKeyguard, fromShadeLocked /* animate */);
mStackScroller.setExpandingEnabled(!onKeyguard);
@@ -4721,7 +4720,7 @@
return;
}
- int userId = mCurrentUserId;
+ int userId = mLockscreenUserManager.getCurrentUserId();
ExpandableNotificationRow row = null;
if (expandView instanceof ExpandableNotificationRow) {
row = (ExpandableNotificationRow) expandView;
@@ -4733,9 +4732,11 @@
userId = row.getStatusBarNotification().getUserId();
}
}
- boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId)
- || !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer();
- if (isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
+ boolean fullShadeNeedsBouncer = !mLockscreenUserManager.
+ userAllowsPrivateNotificationsInPublic(mLockscreenUserManager.getCurrentUserId())
+ || !mLockscreenUserManager.shouldShowLockscreenNotifications()
+ || mFalsingManager.shouldEnforceBouncer();
+ if (mLockscreenUserManager.isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
mLeaveOpenOnKeyguardHide = true;
showBouncerIfKeyguard();
mDraggedDownRow = row;
@@ -4814,19 +4815,12 @@
mPendingWorkRemoteInputView = clicked;
}
- private boolean isAnyProfilePublicMode() {
- for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
- if (isLockscreenPublicMode(mCurrentProfiles.valueAt(i).id)) {
- return true;
- }
- }
- return false;
- }
-
- protected void onWorkChallengeChanged() {
+ @Override
+ public void onWorkChallengeChanged() {
updatePublicMode();
updateNotifications();
- if (mPendingWorkRemoteInputView != null && !isAnyProfilePublicMode()) {
+ if (mPendingWorkRemoteInputView != null
+ && !mLockscreenUserManager.isAnyProfilePublicMode()) {
// Expand notification panel and the notification row, then click on remote input view
final Runnable clickPendingViewRunnable = () -> {
final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView;
@@ -4914,6 +4908,7 @@
if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing);
updateHideIconsForBouncer(true /* animate */);
recomputeDisableFlags(true /* animate */);
+ updateScrimController();
}
public void cancelCurrentTouch() {
@@ -4965,12 +4960,10 @@
mStackScroller.setAnimationsEnabled(true);
mVisualStabilityManager.setScreenOn(true);
mNotificationPanel.setTouchDisabled(false);
-
- maybePrepareWakeUpFromAod();
-
mDozeServiceHost.stopDozing();
updateVisibleToUser();
updateIsKeyguard();
+ updateScrimController();
}
};
@@ -4980,18 +4973,16 @@
mFalsingManager.onScreenTurningOn();
mNotificationPanel.onScreenTurningOn();
- maybePrepareWakeUpFromAod();
-
if (mLaunchCameraOnScreenTurningOn) {
mNotificationPanel.launchCamera(false, mLastCameraLaunchSource);
mLaunchCameraOnScreenTurningOn = false;
}
+
+ updateScrimController();
}
@Override
public void onScreenTurnedOn() {
- mScrimController.wakeUpFromAod();
- mDozeScrimController.onScreenTurnedOn();
}
@Override
@@ -5009,13 +5000,6 @@
return mWakefulnessLifecycle.getWakefulness();
}
- private void maybePrepareWakeUpFromAod() {
- int wakefulness = mWakefulnessLifecycle.getWakefulness();
- if (mDozing && wakefulness == WAKEFULNESS_WAKING && !isPulsing()) {
- mScrimController.prepareWakeUpFromAod();
- }
- }
-
private void vibrateForCameraGesture() {
// Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
mVibrator.vibrate(mCameraLaunchGestureVibePattern, -1 /* repeat */);
@@ -5098,12 +5082,12 @@
if (!mDeviceInteractive) {
// Avoid flickering of the scrim when we instant launch the camera and the bouncer
// comes on.
- mScrimController.dontAnimateBouncerChangesUntilNextFrame();
mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
}
if (isScreenTurningOnOrOn()) {
if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Launching camera");
mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source);
+ updateScrimController();
} else {
// We need to defer the camera launch until the screen comes on, since otherwise
// we will dismiss us too early since we are waiting on an activity to be drawn and
@@ -5116,12 +5100,14 @@
}
boolean isCameraAllowedByAdmin() {
- if (mDevicePolicyManager.getCameraDisabled(null, mCurrentUserId)) {
+ if (mDevicePolicyManager.getCameraDisabled(null,
+ mLockscreenUserManager.getCurrentUserId())) {
return false;
} else if (mStatusBarKeyguardViewManager == null ||
(isKeyguardShowing() && isKeyguardSecure())) {
// Check if the admin has disabled the camera specifically for the keyguard
- return (mDevicePolicyManager.getKeyguardDisabledFeatures(null, mCurrentUserId)
+ return (mDevicePolicyManager.
+ getKeyguardDisabledFeatures(null, mLockscreenUserManager.getCurrentUserId())
& DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) == 0;
}
@@ -5140,20 +5126,22 @@
public void notifyFpAuthModeChanged() {
updateDozing();
+ updateScrimController();
}
private void updateDozing() {
Trace.beginSection("StatusBar#updateDozing");
// When in wake-and-unlock while pulsing, keep dozing state until fully unlocked.
- mDozing = mDozingRequested && mState == StatusBarState.KEYGUARD
+ boolean dozing = mDozingRequested && mState == StatusBarState.KEYGUARD
|| mFingerprintUnlockController.getMode()
== FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
// When in wake-and-unlock we may not have received a change to mState
// but we still should not be dozing, manually set to false.
if (mFingerprintUnlockController.getMode() ==
FingerprintUnlockController.MODE_WAKE_AND_UNLOCK) {
- mDozing = false;
+ dozing = false;
}
+ mDozing = dozing;
mStatusBarWindowManager.setDozing(mDozing);
mStatusBarKeyguardViewManager.setDozing(mDozing);
if (mAmbientIndicationContainer instanceof DozeReceiver) {
@@ -5163,6 +5151,24 @@
Trace.endSection();
}
+ public void updateScrimController() {
+ if (mBouncerShowing) {
+ mScrimController.transitionTo(ScrimState.BOUNCER);
+ } else if (mLaunchCameraOnScreenTurningOn || isInLaunchTransition()) {
+ mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
+ } else if (mBrightnessMirrorVisible) {
+ mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR);
+ } else if (isPulsing()) {
+ // Handled in DozeScrimController#setPulsing
+ } else if (mDozing) {
+ mScrimController.transitionTo(ScrimState.AOD);
+ } else if (mIsKeyguard) {
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ } else {
+ mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
+ }
+ }
+
public boolean isKeyguardShowing() {
if (mStatusBarKeyguardViewManager == null) {
Slog.i(TAG, "isKeyguardShowing() called before startKeyguard(), returning true");
@@ -5222,7 +5228,6 @@
}
mDozeScrimController.pulse(new PulseCallback() {
-
@Override
public void onPulseStarted() {
callback.onPulseStarted();
@@ -5307,11 +5312,6 @@
}
@Override
- public void abortPulsing() {
- mDozeScrimController.abortPulsing();
- }
-
- @Override
public void extendPulse() {
mDozeScrimController.extendPulse();
}
@@ -5347,7 +5347,7 @@
@Override
public void setAodDimmingScrim(float scrimOpacity) {
- mDozeScrimController.setAodDimmingScrim(scrimOpacity);
+ ScrimState.AOD.setAodFrontScrimAlpha(scrimOpacity);
}
public void dispatchDoubleTap(float viewX, float viewY) {
@@ -5397,8 +5397,6 @@
// handling reordering
protected final VisualStabilityManager mVisualStabilityManager = new VisualStabilityManager();
- protected int mCurrentUserId = 0;
- final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
protected AccessibilityManager mAccessibilityManager;
@@ -5425,11 +5423,6 @@
protected PowerManager mPowerManager;
protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- // public mode, private notifications, etc
- private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
- private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
- private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
-
private UserManager mUserManager;
protected KeyguardManager mKeyguardManager;
@@ -5447,8 +5440,6 @@
protected RecentsComponent mRecents;
- protected int mZenMode;
-
protected NotificationShelf mNotificationShelf;
protected DismissView mDismissView;
protected EmptyShadeView mEmptyShadeView;
@@ -5487,30 +5478,6 @@
}
};
- protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange) {
- final int mode = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
- setZenMode(mode);
-
- updateLockscreenNotificationSetting();
- }
- };
-
- private final ContentObserver mLockscreenSettingsObserver = new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange) {
- // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS or
- // LOCK_SCREEN_SHOW_NOTIFICATIONS, so we just dump our cache ...
- mUsersAllowingPrivateNotifications.clear();
- mUsersAllowingNotifications.clear();
- // ... and refresh all the notifications
- updateLockscreenNotificationSetting();
- updateNotifications();
- }
- };
-
private final RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
@Override
@@ -5537,7 +5504,8 @@
final boolean isActivity = pendingIntent.isActivity();
if (isActivity) {
final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
- mContext, pendingIntent.getIntent(), mCurrentUserId);
+ mContext, pendingIntent.getIntent(),
+ mLockscreenUserManager.getCurrentUserId());
dismissKeyguardThenExecute(() -> {
try {
ActivityManager.getService().resumeAppSwitches();
@@ -5658,9 +5626,9 @@
row.setUserExpanded(true);
- if (!mAllowLockscreenRemoteInput) {
+ if (!mLockscreenUserManager.shouldAllowLockscreenRemoteInput()) {
final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
- if (isLockscreenPublicMode(userId)) {
+ if (mLockscreenUserManager.isLockscreenPublicMode(userId)) {
onLockedRemoteInput(row, view);
return true;
}
@@ -5716,51 +5684,15 @@
}
};
- private final BroadcastReceiver mBaseBroadcastReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mBannerActionBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- updateCurrentProfilesCache();
- Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
-
- updateLockscreenNotificationSetting();
-
- userSwitched(mCurrentUserId);
- } else if (Intent.ACTION_USER_ADDED.equals(action)) {
- updateCurrentProfilesCache();
- } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
- // Start the overview connection to the launcher service
- Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser();
- } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
- List<ActivityManager.RecentTaskInfo> recentTask = null;
- try {
- recentTask = ActivityManager.getService().getRecentTasks(1,
- ActivityManager.RECENT_WITH_EXCLUDED,
- mCurrentUserId).getList();
- } catch (RemoteException e) {
- // Abandon hope activity manager not running.
- }
- if (recentTask != null && recentTask.size() > 0) {
- UserInfo user = mUserManager.getUserInfo(recentTask.get(0).userId);
- if (user != null && user.isManagedProfile()) {
- Toast toast = Toast.makeText(mContext,
- R.string.managed_profile_foreground_toast,
- Toast.LENGTH_SHORT);
- TextView text = toast.getView().findViewById(android.R.id.message);
- text.setCompoundDrawablesRelativeWithIntrinsicBounds(
- R.drawable.stat_sys_managed_profile_status, 0, 0, 0);
- int paddingPx = mContext.getResources().getDimensionPixelSize(
- R.dimen.managed_profile_toast_padding);
- text.setCompoundDrawablePadding(paddingPx);
- toast.show();
- }
- }
- } else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
+ if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
NotificationManager noMan = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- noMan.cancel(SystemMessage.NOTE_HIDDEN_NOTIFICATIONS);
+ noMan.cancel(com.android.internal.messages.nano.SystemMessageProto.SystemMessage.
+ NOTE_HIDDEN_NOTIFICATIONS);
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
@@ -5772,141 +5704,11 @@
);
}
- } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
- final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
- final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
- if (intentSender != null) {
- try {
- mContext.startIntentSender(intentSender, null, 0, 0, 0);
- } catch (IntentSender.SendIntentException e) {
- /* ignore */
- }
- }
- if (notificationKey != null) {
- try {
- mBarService.onNotificationClick(notificationKey);
- } catch (RemoteException e) {
- /* ignore */
- }
- }
}
}
};
- private final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
-
- if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
- isCurrentProfile(getSendingUserId())) {
- mUsersAllowingPrivateNotifications.clear();
- updateLockscreenNotificationSetting();
- updateNotifications();
- } else if (Intent.ACTION_DEVICE_LOCKED_CHANGED.equals(action)) {
- if (userId != mCurrentUserId && isCurrentProfile(userId)) {
- onWorkChallengeChanged();
- }
- }
- }
- };
-
- private final NotificationListenerWithPlugins mNotificationListener =
- new NotificationListenerWithPlugins() {
- @Override
- public void onListenerConnected() {
- if (DEBUG) Log.d(TAG, "onListenerConnected");
- onPluginConnected();
- final StatusBarNotification[] notifications = getActiveNotifications();
- if (notifications == null) {
- Log.w(TAG, "onListenerConnected unable to get active notifications.");
- return;
- }
- final RankingMap currentRanking = getCurrentRanking();
- mHandler.post(() -> {
- for (StatusBarNotification sbn : notifications) {
- try {
- addNotification(sbn, currentRanking);
- } catch (InflationException e) {
- handleInflationException(sbn, e);
- }
- }
- });
- }
-
- @Override
- public void onNotificationPosted(final StatusBarNotification sbn,
- final RankingMap rankingMap) {
- if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
- if (sbn != null && !onPluginNotificationPosted(sbn, rankingMap)) {
- mHandler.post(() -> {
- processForRemoteInput(sbn.getNotification());
- String key = sbn.getKey();
- mKeysKeptForRemoteInput.remove(key);
- boolean isUpdate = mNotificationData.get(key) != null;
- // In case we don't allow child notifications, we ignore children of
- // notifications that have a summary, since we're not going to show them
- // anyway. This is true also when the summary is canceled,
- // because children are automatically canceled by NoMan in that case.
- if (!ENABLE_CHILD_NOTIFICATIONS
- && mGroupManager.isChildInGroupWithSummary(sbn)) {
- if (DEBUG) {
- Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
- }
-
- // Remove existing notification to avoid stale data.
- if (isUpdate) {
- removeNotification(key, rankingMap);
- } else {
- mNotificationData.updateRanking(rankingMap);
- }
- return;
- }
- try {
- if (isUpdate) {
- updateNotification(sbn, rankingMap);
- } else {
- addNotification(sbn, rankingMap);
- }
- } catch (InflationException e) {
- handleInflationException(sbn, e);
- }
- });
- }
- }
-
- @Override
- public void onNotificationRemoved(StatusBarNotification sbn,
- final RankingMap rankingMap) {
- if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
- if (sbn != null && !onPluginNotificationRemoved(sbn, rankingMap)) {
- final String key = sbn.getKey();
- mHandler.post(() -> removeNotification(key, rankingMap));
- }
- }
-
- @Override
- public void onNotificationRankingUpdate(final RankingMap rankingMap) {
- if (DEBUG) Log.d(TAG, "onRankingUpdate");
- if (rankingMap != null) {
- RankingMap r = onPluginRankingUpdate(rankingMap);
- mHandler.post(() -> updateNotificationRanking(r));
- }
- }
-
- };
-
- private void updateCurrentProfilesCache() {
- synchronized (mCurrentProfiles) {
- mCurrentProfiles.clear();
- if (mUserManager != null) {
- for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
- mCurrentProfiles.put(user.id, user);
- }
- }
- }
- }
+ protected NotificationListener mNotificationListener;
protected void notifyUserAboutHiddenNotifications() {
if (0 != Settings.Secure.getInt(mContext.getContentResolver(),
@@ -5962,9 +5764,9 @@
final int notificationUserId = n.getUserId();
if (DEBUG && MULTIUSER_DEBUG) {
Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d", n,
- mCurrentUserId, notificationUserId));
+ mLockscreenUserManager.getCurrentUserId(), notificationUserId));
}
- return isCurrentProfile(notificationUserId);
+ return mLockscreenUserManager.isCurrentProfile(notificationUserId);
}
protected void setNotificationShown(StatusBarNotification n) {
@@ -5979,12 +5781,6 @@
}
}
- protected boolean isCurrentProfile(int userId) {
- synchronized (mCurrentProfiles) {
- return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
- }
- }
-
@Override
public NotificationGroupManager getGroupManager() {
return mGroupManager;
@@ -6071,89 +5867,14 @@
KeyboardShortcuts.dismiss();
}
- /**
- * Save the current "public" (locked and secure) state of the lockscreen.
- */
- public void setLockscreenPublicMode(boolean publicMode, int userId) {
- mLockscreenPublicMode.put(userId, publicMode);
- }
-
- public boolean isLockscreenPublicMode(int userId) {
- if (userId == UserHandle.USER_ALL) {
- return mLockscreenPublicMode.get(mCurrentUserId, false);
- }
- return mLockscreenPublicMode.get(userId, false);
- }
-
- /**
- * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
- * "public" (secure & locked) mode?
- */
- public boolean userAllowsNotificationsInPublic(int userHandle) {
- if (userHandle == UserHandle.USER_ALL) {
- return true;
- }
-
- if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
- final boolean allowed = 0 != Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
- mUsersAllowingNotifications.append(userHandle, allowed);
- return allowed;
- }
-
- return mUsersAllowingNotifications.get(userHandle);
- }
-
- /**
- * Has the given user chosen to allow their private (full) notifications to be shown even
- * when the lockscreen is in "public" (secure & locked) mode?
- */
- public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
- if (userHandle == UserHandle.USER_ALL) {
- return true;
- }
-
- if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
- final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
- final boolean allowedByDpm = adminAllowsUnredactedNotifications(userHandle);
- final boolean allowed = allowedByUser && allowedByDpm;
- mUsersAllowingPrivateNotifications.append(userHandle, allowed);
- return allowed;
- }
-
- return mUsersAllowingPrivateNotifications.get(userHandle);
- }
-
- private boolean adminAllowsUnredactedNotifications(int userHandle) {
- if (userHandle == UserHandle.USER_ALL) {
- return true;
- }
- final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
- userHandle);
- return (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
- }
-
- /**
- * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
- * If so, notifications should be hidden.
- */
@Override // NotificationData.Environment
public boolean shouldHideNotifications(int userId) {
- return isLockscreenPublicMode(userId) && !userAllowsNotificationsInPublic(userId)
- || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId));
+ return mLockscreenUserManager.shouldHideNotifications(userId);
}
- /**
- * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
- * package-specific override.
- */
@Override // NotificationDate.Environment
public boolean shouldHideNotifications(String key) {
- return isLockscreenPublicMode(mCurrentUserId)
- && mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_SECRET;
+ return mLockscreenUserManager.shouldHideNotifications(key);
}
/**
@@ -6161,7 +5882,7 @@
*/
@Override // NotificationData.Environment
public boolean isSecurelyLocked(int userId) {
- return isLockscreenPublicMode(userId);
+ return mLockscreenUserManager.isLockscreenPublicMode(userId);
}
/**
@@ -6242,7 +5963,7 @@
private void updateNotification(Entry entry, PackageManager pmUser,
StatusBarNotification sbn, ExpandableNotificationRow row) {
- row.setNeedsRedaction(needsRedaction(entry));
+ row.setNeedsRedaction(mLockscreenUserManager.needsRedaction(entry));
boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey());
boolean isUpdate = mNotificationData.get(entry.key) != null;
boolean wasLowPriority = row.isLowPriority();
@@ -6274,57 +5995,12 @@
row.updateNotification(entry);
}
- /**
- * Adds RemoteInput actions from the WearableExtender; to be removed once more apps support this
- * via first-class API.
- *
- * TODO: Remove once enough apps specify remote inputs on their own.
- */
- private void processForRemoteInput(Notification n) {
- if (!ENABLE_REMOTE_INPUT) return;
-
- if (n.extras != null && n.extras.containsKey("android.wearable.EXTENSIONS") &&
- (n.actions == null || n.actions.length == 0)) {
- Notification.Action viableAction = null;
- Notification.WearableExtender we = new Notification.WearableExtender(n);
-
- List<Notification.Action> actions = we.getActions();
- final int numActions = actions.size();
-
- for (int i = 0; i < numActions; i++) {
- Notification.Action action = actions.get(i);
- if (action == null) {
- continue;
- }
- RemoteInput[] remoteInputs = action.getRemoteInputs();
- if (remoteInputs == null) {
- continue;
- }
- for (RemoteInput ri : remoteInputs) {
- if (ri.getAllowFreeFormInput()) {
- viableAction = action;
- break;
- }
- }
- if (viableAction != null) {
- break;
- }
- }
-
- if (viableAction != null) {
- Notification.Builder rebuilder = Notification.Builder.recoverBuilder(mContext, n);
- rebuilder.setActions(viableAction);
- rebuilder.build(); // will rewrite n
- }
- }
- }
-
public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
if (!isDeviceProvisioned()) return;
final boolean afterKeyguardGone = intent.isActivity()
&& PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
- mCurrentUserId);
+ mLockscreenUserManager.getCurrentUserId());
dismissKeyguardThenExecute(() -> {
new Thread(() -> {
try {
@@ -6399,7 +6075,7 @@
final boolean afterKeyguardGone = intent.isActivity()
&& PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
- mCurrentUserId);
+ mLockscreenUserManager.getCurrentUserId());
dismissKeyguardThenExecute(() -> {
if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
// Release the HUN notification to the shade.
@@ -6653,9 +6329,11 @@
int userId = entry.notification.getUserId();
boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
entry.notification) && !entry.row.isRemoved();
- boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
+ boolean showOnKeyguard = mLockscreenUserManager.shouldShowOnKeyguard(entry
+ .notification);
if (suppressedSummary
- || (isLockscreenPublicMode(userId) && !mShowLockscreenNotifications)
+ || (mLockscreenUserManager.isLockscreenPublicMode(userId)
+ && !mLockscreenUserManager.shouldShowLockscreenNotifications())
|| (onKeyguard && !showOnKeyguard)) {
entry.row.setVisibility(View.GONE);
} else {
@@ -6705,49 +6383,9 @@
mScrimController.setNotificationCount(mStackScroller.getNotGoneChildCount());
}
- public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
- return mShowLockscreenNotifications
- && ((mDisabled2 & DISABLE2_NOTIFICATION_SHADE) == 0)
- && !mNotificationData.isAmbient(sbn.getKey());
- }
-
- // extended in StatusBar
- protected void setShowLockscreenNotifications(boolean show) {
- mShowLockscreenNotifications = show;
- }
-
- protected void setLockScreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
- mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
- }
-
- protected void updateLockscreenNotificationSetting() {
- final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
- 1,
- mCurrentUserId) != 0;
- final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(
- null /* admin */, mCurrentUserId);
- final boolean allowedByDpm = (dpmFlags
- & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
-
- setShowLockscreenNotifications(show && allowedByDpm);
-
- if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
- final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
- 0,
- mCurrentUserId) != 0;
- final boolean remoteInputDpm =
- (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
-
- setLockScreenAllowRemoteInput(remoteInput && remoteInputDpm);
- } else {
- setLockScreenAllowRemoteInput(false);
- }
- }
-
- public void updateNotification(StatusBarNotification notification, RankingMap ranking)
- throws InflationException {
+ // TODO: Move this to NotificationEntryManager once it is created.
+ private void updateNotificationInternal(StatusBarNotification notification,
+ RankingMap ranking) throws InflationException {
if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
final String key = notification.getKey();
@@ -6797,6 +6435,15 @@
setAreThereNotifications();
}
+ @Override
+ public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
+ try {
+ updateNotificationInternal(notification, ranking);
+ } catch (InflationException e) {
+ handleInflationException(notification, e);
+ }
+ }
+
protected void notifyHeadsUpGoingToSleep() {
maybeEscalateHeadsUp();
}
@@ -6859,9 +6506,11 @@
}
if (mIsOccluded && !isDozing()) {
- boolean devicePublic = isLockscreenPublicMode(mCurrentUserId);
- boolean userPublic = devicePublic || isLockscreenPublicMode(sbn.getUserId());
- boolean needsRedaction = needsRedaction(entry);
+ boolean devicePublic = mLockscreenUserManager.
+ isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
+ boolean userPublic = devicePublic
+ || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
+ boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry);
if (userPublic && needsRedaction) {
return false;
}
@@ -6977,13 +6626,13 @@
}
@Override
- public int getCurrentUserId() {
- return mCurrentUserId;
+ public NotificationData getNotificationData() {
+ return mNotificationData;
}
@Override
- public NotificationData getNotificationData() {
- return mNotificationData;
+ public Handler getHandler() {
+ return mHandler;
}
@Override
@@ -6991,12 +6640,17 @@
return mLatestRankingMap;
}
- final NotificationInfo.CheckSaveListener mCheckSaveListener =
+ @Override
+ public Set<String> getKeysKeptForRemoteInput() {
+ return mKeysKeptForRemoteInput;
+ }
+
+ private final NotificationInfo.CheckSaveListener mCheckSaveListener =
(Runnable saveImportance, StatusBarNotification sbn) -> {
// If the user has security enabled, show challenge if the setting is changed.
- if (isLockscreenPublicMode(sbn.getUser().getIdentifier()) && (
- mState == StatusBarState.KEYGUARD
- || mState == StatusBarState.SHADE_LOCKED)) {
+ if (mLockscreenUserManager.isLockscreenPublicMode(sbn.getUser().getIdentifier())
+ && (mState == StatusBarState.KEYGUARD ||
+ mState == StatusBarState.SHADE_LOCKED)) {
onLockedNotificationImportanceChange(() -> {
saveImportance.run();
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index bcde556..dacd3d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -24,7 +24,6 @@
import android.content.Context;
import android.os.Bundle;
import android.os.SystemClock;
-import android.os.Trace;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -34,7 +33,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.keyguard.LatencyTracker;
+import com.android.internal.util.LatencyTracker;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dependency;
@@ -71,17 +70,14 @@
protected final Context mContext;
private final StatusBarWindowManager mStatusBarWindowManager;
- private final boolean mDisplayBlanksAfterDoze;
protected LockPatternUtils mLockPatternUtils;
protected ViewMediatorCallback mViewMediatorCallback;
protected StatusBar mStatusBar;
- private ScrimController mScrimController;
private FingerprintUnlockController mFingerprintUnlockController;
private ViewGroup mContainer;
- private boolean mScreenTurnedOn;
protected KeyguardBouncer mBouncer;
protected boolean mShowing;
protected boolean mOccluded;
@@ -95,12 +91,10 @@
private boolean mLastBouncerDismissible;
protected boolean mLastRemoteInputActive;
private boolean mLastDozing;
- private boolean mLastDeferScrimFadeOut;
private int mLastFpMode;
private OnDismissAction mAfterKeyguardGoneAction;
private final ArrayList<Runnable> mAfterKeyguardGoneRunnables = new ArrayList<>();
- private boolean mDeferScrimFadeOut;
// Dismiss action to be launched when we stop dozing or the keyguard is gone.
private DismissWithActionRequest mPendingWakeupAction;
@@ -125,18 +119,14 @@
mLockPatternUtils = lockPatternUtils;
mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitorCallback);
- mDisplayBlanksAfterDoze = context.getResources().getBoolean(
- com.android.internal.R.bool.config_displayBlanksAfterDoze);
}
public void registerStatusBar(StatusBar statusBar,
ViewGroup container,
- ScrimController scrimController,
FingerprintUnlockController fingerprintUnlockController,
DismissCallbackRegistry dismissCallbackRegistry) {
mStatusBar = statusBar;
mContainer = container;
- mScrimController = scrimController;
mFingerprintUnlockController = fingerprintUnlockController;
mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry);
@@ -149,7 +139,6 @@
public void show(Bundle options) {
mShowing = true;
mStatusBarWindowManager.setKeyguardShowing(true);
- mScrimController.abortKeyguardFadingOut();
reset(true /* hideBouncerWhenShowing */);
}
@@ -253,15 +242,7 @@
}
public void onScreenTurnedOn() {
- Trace.beginSection("StatusBarKeyguardViewManager#onScreenTurnedOn");
- mScreenTurnedOn = true;
- if (mDeferScrimFadeOut) {
- mDeferScrimFadeOut = false;
- animateScrimControllerKeyguardFadingOut(0, WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS,
- true /* skipFirstFrame */);
- updateStates();
- }
- Trace.endSection();
+ // TODO: remove
}
@Override
@@ -285,7 +266,7 @@
}
public void onScreenTurnedOff() {
- mScreenTurnedOn = false;
+ // TODO: remove
}
public void notifyDeviceWakeUpRequested() {
@@ -374,10 +355,6 @@
mStatusBarWindowManager.setKeyguardFadingAway(true);
hideBouncer(true /* destroyView */);
updateStates();
- mScrimController.animateKeyguardFadingOut(
- StatusBar.FADE_KEYGUARD_START_DELAY,
- StatusBar.FADE_KEYGUARD_DURATION, null,
- false /* skipFirstFrame */);
}
}, new Runnable() {
@Override
@@ -400,36 +377,16 @@
mFingerprintUnlockController.startKeyguardFadingAway();
hideBouncer(true /* destroyView */);
if (wakeUnlockPulsing) {
- mStatusBarWindowManager.setKeyguardFadingAway(true);
mStatusBar.fadeKeyguardWhilePulsing();
- animateScrimControllerKeyguardFadingOut(delay, fadeoutDuration,
- mStatusBar::hideKeyguard, false /* skipFirstFrame */);
+ wakeAndUnlockDejank();
} else {
mFingerprintUnlockController.startKeyguardFadingAway();
mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
boolean staying = mStatusBar.hideKeyguard();
if (!staying) {
mStatusBarWindowManager.setKeyguardFadingAway(true);
- if (mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK) {
- boolean turnedOnSinceAuth =
- mFingerprintUnlockController.hasScreenTurnedOnSinceAuthenticating();
- if (!mScreenTurnedOn || mDisplayBlanksAfterDoze && !turnedOnSinceAuth) {
- // Not ready to animate yet; either because the screen is not on yet,
- // or it is on but will turn off before waking out of doze.
- mDeferScrimFadeOut = true;
- } else {
-
- // Screen is already on, don't defer with fading out.
- animateScrimControllerKeyguardFadingOut(0,
- WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS,
- true /* skipFirstFrame */);
- }
- } else {
- animateScrimControllerKeyguardFadingOut(delay, fadeoutDuration,
- false /* skipFirstFrame */);
- }
+ wakeAndUnlockDejank();
} else {
- mScrimController.animateGoingToFullShade(delay, fadeoutDuration);
mStatusBar.finishKeyguardFadingAway();
mFingerprintUnlockController.finishKeyguardFadingAway();
}
@@ -449,30 +406,17 @@
mBouncer.prepare();
}
- private void animateScrimControllerKeyguardFadingOut(long delay, long duration,
- boolean skipFirstFrame) {
- animateScrimControllerKeyguardFadingOut(delay, duration, null /* endRunnable */,
- skipFirstFrame);
+ public void onKeyguardFadedAway() {
+ mContainer.postDelayed(() -> mStatusBarWindowManager.setKeyguardFadingAway(false),
+ 100);
+ mStatusBar.finishKeyguardFadingAway();
+ mFingerprintUnlockController.finishKeyguardFadingAway();
+ WindowManagerGlobal.getInstance().trimMemory(
+ ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
+
}
- private void animateScrimControllerKeyguardFadingOut(long delay, long duration,
- final Runnable endRunnable, boolean skipFirstFrame) {
- Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "Fading out", 0);
- mScrimController.animateKeyguardFadingOut(delay, duration, new Runnable() {
- @Override
- public void run() {
- if (endRunnable != null) {
- endRunnable.run();
- }
- mContainer.postDelayed(() -> mStatusBarWindowManager.setKeyguardFadingAway(false),
- 100);
- mStatusBar.finishKeyguardFadingAway();
- mFingerprintUnlockController.finishKeyguardFadingAway();
- WindowManagerGlobal.getInstance().trimMemory(
- ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
- Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "Fading out", 0);
- }
- }, skipFirstFrame);
+ private void wakeAndUnlockDejank() {
if (mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK
&& LatencyTracker.isEnabled(mContext)) {
DejankUtils.postAfterTraversal(() ->
@@ -593,7 +537,6 @@
if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
mStatusBarWindowManager.setBouncerShowing(bouncerShowing);
mStatusBar.setBouncerShowing(bouncerShowing);
- mScrimController.setBouncerShowing(bouncerShowing);
}
KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
@@ -611,7 +554,6 @@
mLastBouncerDismissible = bouncerDismissible;
mLastRemoteInputActive = remoteInputActive;
mLastDozing = mDozing;
- mLastDeferScrimFadeOut = mDeferScrimFadeOut;
mLastFpMode = mFingerprintUnlockController.getMode();
mStatusBar.onKeyguardViewManagerStatesUpdated();
}
@@ -624,7 +566,7 @@
boolean keyguardShowing = mShowing && !mOccluded;
boolean hideWhileDozing = mDozing && fpMode != MODE_WAKE_AND_UNLOCK_PULSING;
return (!keyguardShowing && !hideWhileDozing || mBouncer.isShowing()
- || mRemoteInputActive) && !mDeferScrimFadeOut;
+ || mRemoteInputActive);
}
/**
@@ -634,7 +576,7 @@
boolean keyguardShowing = mLastShowing && !mLastOccluded;
boolean hideWhileDozing = mLastDozing && mLastFpMode != MODE_WAKE_AND_UNLOCK_PULSING;
return (!keyguardShowing && !hideWhileDozing || mLastBouncerShowing
- || mLastRemoteInputActive) && !mLastDeferScrimFadeOut;
+ || mLastRemoteInputActive);
}
public boolean shouldDismissOnMenuPressed() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index d7f11f7..4accd86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -248,7 +248,6 @@
public void setTouchActive(boolean touchActive) {
mTouchActive = touchActive;
- mStackScrollLayout.setTouchActive(touchActive);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index b0553d7..a011952 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy;
+import android.annotation.NonNull;
import android.util.ArraySet;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
@@ -26,46 +27,47 @@
import com.android.internal.util.Preconditions;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBarWindowView;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+import java.util.function.Consumer;
+
/**
* Controls showing and hiding of the brightness mirror.
*/
public class BrightnessMirrorController
implements CallbackController<BrightnessMirrorController.BrightnessMirrorListener> {
- private final NotificationStackScrollLayout mStackScroller;
- public long TRANSITION_DURATION_OUT = 150;
- public long TRANSITION_DURATION_IN = 200;
+ private final static long TRANSITION_DURATION_OUT = 150;
+ private final static long TRANSITION_DURATION_IN = 200;
private final StatusBarWindowView mStatusBarWindow;
- private final ScrimController mScrimController;
+ private final NotificationStackScrollLayout mStackScroller;
+ private final Consumer<Boolean> mVisibilityCallback;
private final View mNotificationPanel;
private final ArraySet<BrightnessMirrorListener> mBrightnessMirrorListeners = new ArraySet<>();
private final int[] mInt2Cache = new int[2];
private View mBrightnessMirror;
public BrightnessMirrorController(StatusBarWindowView statusBarWindow,
- ScrimController scrimController) {
+ @NonNull Consumer<Boolean> visibilityCallback) {
mStatusBarWindow = statusBarWindow;
mBrightnessMirror = statusBarWindow.findViewById(R.id.brightness_mirror);
mNotificationPanel = statusBarWindow.findViewById(R.id.notification_panel);
mStackScroller = statusBarWindow.findViewById(R.id.notification_stack_scroller);
- mScrimController = scrimController;
+ mVisibilityCallback = visibilityCallback;
}
public void showMirror() {
mBrightnessMirror.setVisibility(View.VISIBLE);
mStackScroller.setFadingOut(true);
- mScrimController.forceHideScrims(true /* hide */, true /* animated */);
+ mVisibilityCallback.accept(true);
outAnimation(mNotificationPanel.animate())
.withLayer();
}
public void hideMirror() {
- mScrimController.forceHideScrims(false /* hide */, true /* animated */);
+ mVisibilityCallback.accept(false);
inAnimation(mNotificationPanel.animate())
.withLayer()
.withEndAction(() -> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 874f0d9..4ee4ef4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -39,6 +39,8 @@
import java.util.ArrayList;
import java.util.List;
+import static com.android.settingslib.Utils.updateLocationMode;
+
/**
* A controller to manage changes of location related states and update the views accordingly.
*/
@@ -106,12 +108,13 @@
final ContentResolver cr = mContext.getContentResolver();
// When enabling location, a user consent dialog will pop up, and the
// setting won't be fully enabled until the user accepts the agreement.
+ int currentMode = Settings.Secure.getIntForUser(cr, Settings.Secure.LOCATION_MODE,
+ Settings.Secure.LOCATION_MODE_OFF, currentUserId);
int mode = enabled
? Settings.Secure.LOCATION_MODE_PREVIOUS : Settings.Secure.LOCATION_MODE_OFF;
// QuickSettings always runs as the owner, so specifically set the settings
// for the current foreground user.
- return Settings.Secure
- .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId);
+ return updateLocationMode(mContext, currentMode, mode, currentUserId);
}
/**
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 652f8bb..8516278 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -288,7 +288,7 @@
String description = null;
// Only send data sim callbacks to QS.
if (mCurrentState.dataSim) {
- qsTypeIcon = showDataIcon ? icons.mQsDataType : 0;
+ qsTypeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.mQsDataType : 0;
qsIcon = new IconState(mCurrentState.enabled
&& !mCurrentState.isEmergency, getQsCurrentIconId(), contentDescription);
description = mCurrentState.isEmergency ? null : mCurrentState.networkName;
@@ -300,7 +300,7 @@
&& !mCurrentState.carrierNetworkChangeMode
&& mCurrentState.activityOut;
showDataIcon &= mCurrentState.isDefault || dataDisabled;
- int typeIcon = showDataIcon ? icons.mDataType : 0;
+ int typeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.mDataType : 0;
callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
activityIn, activityOut, dataContentDescription, description, icons.mIsWide,
mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming);
@@ -460,7 +460,7 @@
mCurrentState.roaming = isRoaming();
if (isCarrierNetworkChangeActive()) {
mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE;
- } else if (isDataDisabled()) {
+ } else if (isDataDisabled() && !mConfig.alwaysShowDataRatIcon) {
mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED;
}
if (isEmergencyOnly() != mCurrentState.isEmergency) {
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 40ee838..baf0ebf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -29,7 +29,9 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
+import android.os.PersistableBundle;
import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionInfo;
@@ -245,6 +247,7 @@
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
mContext.registerReceiver(this, filter, null, mReceiverHandler);
mListening = true;
@@ -426,6 +429,14 @@
// emergency state.
recalculateEmergency();
}
+ } else if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
+ mConfig = Config.readConfig(mContext);
+ mReceiverHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ handleConfigurationChanged();
+ }
+ });
} else {
int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
@@ -969,6 +980,7 @@
boolean hideLtePlus = false;
boolean hspaDataDistinguishable;
boolean inflateSignalStrengths = false;
+ boolean alwaysShowDataRatIcon = false;
static Config readConfig(Context context) {
Config config = new Config();
@@ -982,6 +994,14 @@
res.getBoolean(R.bool.config_hspa_data_distinguishable);
config.hideLtePlus = res.getBoolean(R.bool.config_hideLtePlus);
config.inflateSignalStrengths = res.getBoolean(R.bool.config_inflateSignalStrength);
+
+ CarrierConfigManager configMgr = (CarrierConfigManager)
+ context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ PersistableBundle b = configMgr.getConfig();
+ if (b != null) {
+ config.alwaysShowDataRatIcon = b.getBoolean(
+ CarrierConfigManager.KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL);
+ }
return config;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 37b0de4..4fc50442 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -53,11 +53,9 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.notification.NotificationViewWrapper;
-import com.android.systemui.statusbar.stack.ScrollContainer;
import com.android.systemui.statusbar.stack.StackStateAnimator;
/**
@@ -82,8 +80,6 @@
private NotificationData.Entry mEntry;
- private ScrollContainer mScrollContainer;
- private View mScrollContainerChild;
private boolean mRemoved;
private int mRevealCx;
@@ -347,41 +343,16 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- findScrollContainer();
- if (mScrollContainer != null) {
- mScrollContainer.requestDisallowLongPress();
- mScrollContainer.requestDisallowDismiss();
- }
+ mController.requestDisallowLongPressAndDismiss();
}
return super.onInterceptTouchEvent(ev);
}
public boolean requestScrollTo() {
- findScrollContainer();
- mScrollContainer.lockScrollTo(mScrollContainerChild);
+ mController.lockScrollTo(mEntry);
return true;
}
- private void findScrollContainer() {
- if (mScrollContainer == null) {
- mScrollContainerChild = null;
- ViewParent p = this;
- while (p != null) {
- if (mScrollContainerChild == null && p instanceof ExpandableView) {
- mScrollContainerChild = (View) p;
- }
- if (p.getParent() instanceof ScrollContainer) {
- mScrollContainer = (ScrollContainer) p.getParent();
- if (mScrollContainerChild == null) {
- mScrollContainerChild = (View) p;
- }
- break;
- }
- p = p.getParent();
- }
- }
- }
-
public boolean isActive() {
return mEditText.isFocused() && mEditText.isEnabled();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
index 722874b..f258fb1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
@@ -24,6 +24,7 @@
boolean isRotationLockAffordanceVisible();
boolean isRotationLocked();
void setRotationLocked(boolean locked);
+ void setRotationLockedAtAngle(boolean locked, int rotation);
public interface RotationLockControllerCallback {
void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
index 4f96496..5418dc1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
@@ -63,6 +63,10 @@
RotationPolicy.setRotationLock(mContext, locked);
}
+ public void setRotationLockedAtAngle(boolean locked, int rotation){
+ RotationPolicy.setRotationLockAtAngle(mContext, locked, rotation);
+ }
+
public boolean isRotationLockAffordanceVisible() {
return RotationPolicy.isRotationLockToggleVisible(mContext);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java
index 527addf..f5ae88b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java
@@ -154,7 +154,9 @@
avatar = new UserIconDrawable(avatarSize)
.setIcon(rawAvatar).setBadgeIfManagedUser(mContext, userId).bake();
} else {
- avatar = UserIcons.getDefaultUserIcon(isGuest? UserHandle.USER_NULL : userId,
+ avatar = UserIcons.getDefaultUserIcon(
+ context.getResources(),
+ isGuest? UserHandle.USER_NULL : userId,
lightIcon);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 0f498bc..7006d38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -747,7 +747,8 @@
if (item.isAddUser) {
return context.getDrawable(R.drawable.ic_add_circle_qs);
}
- Drawable icon = UserIcons.getDefaultUserIcon(item.resolveId(), /* light= */ false);
+ Drawable icon = UserIcons.getDefaultUserIcon(
+ context.getResources(), item.resolveId(), /* light= */ false);
if (item.isGuest) {
icon.setColorFilter(Utils.getColorAttr(context, android.R.attr.colorForeground),
Mode.SRC_IN);
@@ -959,7 +960,7 @@
}
int id = user.id;
Bitmap icon = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(
- id, /* light= */ false));
+ mContext.getResources(), id, /* light= */ false));
mUserManager.setUserIcon(id, icon);
switchToUserId(id);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationProperties.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationProperties.java
index ebb0a6d..2f6e658 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationProperties.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationProperties.java
@@ -36,7 +36,12 @@
* @return an animation filter for this animation.
*/
public AnimationFilter getAnimationFilter() {
- return new AnimationFilter();
+ return new AnimationFilter() {
+ @Override
+ public boolean shouldAnimateProperty(Property property) {
+ return true;
+ }
+ };
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
index e0fd481..0650e23 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
@@ -95,6 +95,12 @@
public boolean inShelf;
/**
+ * A state indicating whether a headsup is currently fully visible, even when not scrolled.
+ * Only valid if the view is heads upped.
+ */
+ public boolean headsUpIsVisible;
+
+ /**
* How much the child overlaps with the previous child on top. This is used to
* show the background properly when the child on top is translating away.
*/
@@ -126,6 +132,7 @@
clipTopAmount = svs.clipTopAmount;
notGoneIndex = svs.notGoneIndex;
location = svs.location;
+ headsUpIsVisible = svs.headsUpIsVisible;
}
}
@@ -175,6 +182,10 @@
expandableView.setTransformingInShelf(false);
expandableView.setInShelf(inShelf);
+
+ if (headsUpIsVisible) {
+ expandableView.setHeadsUpIsVisible();
+ }
}
}
@@ -229,6 +240,10 @@
expandableView.setTransformingInShelf(true);
}
expandableView.setInShelf(this.inShelf);
+
+ if (headsUpIsVisible) {
+ expandableView.setHeadsUpIsVisible();
+ }
}
private void startHeightAnimation(final ExpandableView child, AnimationProperties properties) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index fe53104..c0241e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -1260,4 +1260,17 @@
public boolean isUserLocked() {
return mUserLocked;
}
+
+ public void setCurrentBottomRoundness(float currentBottomRoundness) {
+ boolean last = true;
+ for (int i = mChildren.size() - 1; i >= 0; i--) {
+ ExpandableNotificationRow child = mChildren.get(i);
+ if (child.getVisibility() == View.GONE) {
+ continue;
+ }
+ float bottomRoundness = last ? currentBottomRoundness : 0.0f;
+ child.setBottomRoundness(bottomRoundness, isShown() /* animate */);
+ last = false;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index efe049a..0f2a2c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -30,6 +30,7 @@
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
@@ -75,6 +76,7 @@
import com.android.systemui.statusbar.DismissView;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.ExpandableOutlineView;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationGuts;
@@ -82,8 +84,10 @@
import com.android.systemui.statusbar.NotificationSnooze;
import com.android.systemui.statusbar.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -108,8 +112,7 @@
public class NotificationStackScrollLayout extends ViewGroup
implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter,
ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener,
- NotificationMenuRowPlugin.OnMenuEventListener, ScrollContainer,
- VisibilityLocationProvider {
+ NotificationMenuRowPlugin.OnMenuEventListener, VisibilityLocationProvider {
public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
private static final String TAG = "StackScroller";
@@ -121,12 +124,23 @@
* Sentinel value for no current active pointer. Used by {@link #mActivePointerId}.
*/
private static final int INVALID_POINTER = -1;
+ private static final AnimatableProperty SIDE_PADDINGS = AnimatableProperty.from(
+ "sidePaddings",
+ NotificationStackScrollLayout::setCurrentSidePadding,
+ NotificationStackScrollLayout::getCurrentSidePadding,
+ R.id.side_padding_animator_tag,
+ R.id.side_padding_animator_end_tag,
+ R.id.side_padding_animator_start_tag);
+ private static final AnimationProperties SIDE_PADDING_PROPERTIES =
+ new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
private ExpandHelper mExpandHelper;
private NotificationSwipeHelper mSwipeHelper;
private boolean mSwipingInProgress;
private int mCurrentStackHeight = Integer.MAX_VALUE;
private final Paint mBackgroundPaint = new Paint();
+ private final Path mBackgroundPath = new Path();
+ private final float[] mBackgroundRadii = new float[8];
private final boolean mShouldDrawNotificationBackground;
private float mExpandedHeight;
@@ -157,6 +171,7 @@
private int mTopPadding;
private int mBottomMargin;
private int mBottomInset = 0;
+ private float mCurrentSidePadding;
/**
* The algorithm which calculates the properties for our children
@@ -383,6 +398,9 @@
private int mCachedBackgroundColor;
private boolean mHeadsUpGoingAwayAnimationsAllowed = true;
private Runnable mAnimateScroll = this::animateScroll;
+ private int mCornerRadius;
+ private int mLockscreenSidePaddings;
+ private int mSidePaddings;
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -419,6 +437,8 @@
res.getBoolean(R.bool.config_fadeNotificationsOnDismiss);
updateWillNotDraw();
+ mBackgroundPaint.setAntiAlias(true);
+ mBackgroundPaint.setStyle(Paint.Style.FILL);
if (DEBUG) {
mDebugPaint = new Paint();
mDebugPaint.setColor(0xffff0000);
@@ -466,8 +486,7 @@
protected void onDraw(Canvas canvas) {
if (mShouldDrawNotificationBackground && !mAmbientState.isDark()
&& mCurrentBounds.top < mCurrentBounds.bottom) {
- canvas.drawRect(0, mCurrentBounds.top, getWidth(), mCurrentBounds.bottom,
- mBackgroundPaint);
+ canvas.drawPath(mBackgroundPath, mBackgroundPaint);
}
if (DEBUG) {
@@ -520,8 +539,12 @@
R.dimen.min_top_overscroll_to_qs);
mStatusBarHeight = res.getDimensionPixelOffset(R.dimen.status_bar_height);
mBottomMargin = res.getDimensionPixelSize(R.dimen.notification_panel_margin_bottom);
+ mLockscreenSidePaddings = res.getDimensionPixelSize(
+ R.dimen.notification_lockscreen_side_paddings);
mMinInteractionHeight = res.getDimensionPixelSize(
R.dimen.notification_min_interaction_height);
+ mCornerRadius = res.getDimensionPixelSize(
+ Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius));
}
public void setDrawBackgroundAsSrc(boolean asSrc) {
@@ -601,7 +624,7 @@
if (childViewState == null) {
return false;
}
- if ((childViewState.location &= ExpandableViewState.VISIBLE_LOCATIONS) == 0) {
+ if ((childViewState.location & ExpandableViewState.VISIBLE_LOCATIONS) == 0) {
return false;
}
if (row.getVisibility() != View.VISIBLE) {
@@ -1195,7 +1218,6 @@
mScrollingEnabled = enable;
}
- @Override
public void lockScrollTo(View v) {
if (mForcedScroll == v) {
return;
@@ -1204,7 +1226,6 @@
scrollTo(v);
}
- @Override
public boolean scrollTo(View v) {
ExpandableView expandableView = (ExpandableView) v;
int positionInLinearLayout = getPositionInLinearLayout(v);
@@ -2221,9 +2242,31 @@
mScrimController.setExcludedBackgroundArea(
mFadingOut || mParentNotFullyVisible || mAmbientState.isDark() || mIsClipped ? null
: mCurrentBounds);
+ updateBackgroundPath();
invalidate();
}
+ private void updateBackgroundPath() {
+ mBackgroundPath.reset();
+ float topRoundness = 0;
+ if (mFirstVisibleBackgroundChild != null) {
+ topRoundness = mFirstVisibleBackgroundChild.getCurrentBackgroundRadiusTop();
+ }
+ topRoundness = onKeyguard() ? mCornerRadius : topRoundness;
+ float bottomRoundNess = mCornerRadius;
+ mBackgroundRadii[0] = topRoundness;
+ mBackgroundRadii[1] = topRoundness;
+ mBackgroundRadii[2] = topRoundness;
+ mBackgroundRadii[3] = topRoundness;
+ mBackgroundRadii[4] = bottomRoundNess;
+ mBackgroundRadii[5] = bottomRoundNess;
+ mBackgroundRadii[6] = bottomRoundNess;
+ mBackgroundRadii[7] = bottomRoundNess;
+ mBackgroundPath.addRoundRect(mCurrentSidePadding, mCurrentBounds.top,
+ getWidth() - mCurrentSidePadding, mCurrentBounds.bottom, mBackgroundRadii,
+ Path.Direction.CCW);
+ }
+
/**
* Update the background bounds to the new desired bounds
*/
@@ -2236,6 +2279,8 @@
mBackgroundBounds.left = mTempInt2[0];
mBackgroundBounds.right = mTempInt2[0] + getWidth();
}
+ mBackgroundBounds.left += mCurrentSidePadding;
+ mBackgroundBounds.right -= mCurrentSidePadding;
if (!mIsExpanded) {
mBackgroundBounds.top = 0;
mBackgroundBounds.bottom = 0;
@@ -2820,16 +2865,45 @@
private void updateFirstAndLastBackgroundViews() {
ActivatableNotificationView firstChild = getFirstChildWithBackground();
ActivatableNotificationView lastChild = getLastChildWithBackground();
+ boolean firstChanged = firstChild != mFirstVisibleBackgroundChild;
+ boolean lastChanged = lastChild != mLastVisibleBackgroundChild;
if (mAnimationsEnabled && mIsExpanded) {
- mAnimateNextBackgroundTop = firstChild != mFirstVisibleBackgroundChild;
- mAnimateNextBackgroundBottom = lastChild != mLastVisibleBackgroundChild;
+ mAnimateNextBackgroundTop = firstChanged;
+ mAnimateNextBackgroundBottom = lastChanged;
} else {
mAnimateNextBackgroundTop = false;
mAnimateNextBackgroundBottom = false;
}
+ if (firstChanged && mFirstVisibleBackgroundChild != null
+ && !mFirstVisibleBackgroundChild.isRemoved()) {
+ mFirstVisibleBackgroundChild.setTopRoundness(0.0f,
+ mFirstVisibleBackgroundChild.isShown());
+ }
+ if (lastChanged && mLastVisibleBackgroundChild != null
+ && !mLastVisibleBackgroundChild.isRemoved()) {
+ mLastVisibleBackgroundChild.setBottomRoundness(0.0f,
+ mLastVisibleBackgroundChild.isShown());
+ }
mFirstVisibleBackgroundChild = firstChild;
mLastVisibleBackgroundChild = lastChild;
mAmbientState.setLastVisibleBackgroundChild(lastChild);
+ applyRoundedNess();
+ }
+
+ private void applyRoundedNess() {
+ if (mFirstVisibleBackgroundChild != null) {
+ mFirstVisibleBackgroundChild.setTopRoundness(
+ mStatusBarState == StatusBarState.KEYGUARD ? 1.0f : 0.0f,
+ mFirstVisibleBackgroundChild.isShown()
+ && !mChildrenToAddAnimated.contains(mFirstVisibleBackgroundChild));
+ }
+ if (mLastVisibleBackgroundChild != null) {
+ mLastVisibleBackgroundChild.setBottomRoundness(1.0f,
+ mLastVisibleBackgroundChild.isShown()
+ && !mChildrenToAddAnimated.contains(mLastVisibleBackgroundChild));
+ }
+ updateBackgroundPath();
+ invalidate();
}
private void onViewAddedInternal(View child) {
@@ -2838,6 +2912,7 @@
generateAddAnimation(child, false /* fromMoreCard */);
updateAnimationState(child);
updateChronometerForChild(child);
+ updateCurrentSidePaddings(child);
}
private void updateHideSensitiveForChild(View child) {
@@ -3321,12 +3396,10 @@
}
}
- @Override
public void requestDisallowLongPress() {
cancelLongPress();
}
- @Override
public void requestDisallowDismiss() {
mDisallowDismissInThisMotion = true;
}
@@ -4285,6 +4358,43 @@
public void setStatusBarState(int statusBarState) {
mStatusBarState = statusBarState;
mAmbientState.setStatusBarState(statusBarState);
+ applyRoundedNess();
+ updateSidePaddings();
+ }
+
+ private void updateSidePaddings() {
+ int sidePaddings = mStatusBarState == StatusBarState.KEYGUARD ? mLockscreenSidePaddings : 0;
+ if (sidePaddings != mSidePaddings) {
+ boolean animate = isShown();
+ mSidePaddings = sidePaddings;
+ PropertyAnimator.setProperty(this, SIDE_PADDINGS, sidePaddings,
+ SIDE_PADDING_PROPERTIES, animate);
+ }
+ }
+
+ protected void setCurrentSidePadding(float sidePadding) {
+ mCurrentSidePadding = sidePadding;
+ updateBackground();
+ applySidePaddingsToChildren();
+ }
+
+ private void applySidePaddingsToChildren() {
+ for (int i = 0; i < getChildCount(); i++) {
+ View view = getChildAt(i);
+ updateCurrentSidePaddings(view);
+ }
+ }
+
+ private void updateCurrentSidePaddings(View view) {
+ if (!(view instanceof ExpandableOutlineView)) {
+ return;
+ }
+ ExpandableOutlineView outlineView = (ExpandableOutlineView) view;
+ outlineView.setCurrentSidePaddings(mCurrentSidePadding);
+ }
+
+ protected float getCurrentSidePadding() {
+ return mCurrentSidePadding;
}
public void setExpandingVelocity(float expandingVelocity) {
@@ -4333,10 +4443,6 @@
mAmbientState.getScrollY()));
}
- public void setTouchActive(boolean touchActive) {
- mShelf.setTouchActive(touchActive);
- }
-
/**
* A listener that is notified when some child locations might have changed.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java
deleted file mode 100644
index b9d12ce..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2016 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.stack;
-
-import android.view.View;
-
-/**
- * Interface for container layouts that scroll and listen for long presses. A child that
- * wants to handle long press can use this to cancel the parents long press logic or request
- * to be made visible by scrolling to it.
- */
-public interface ScrollContainer {
- /**
- * Request that the view does not perform long press for the current touch.
- */
- void requestDisallowLongPress();
-
- /**
- * Request that the view is made visible by scrolling to it.
- * Return true if it scrolls.
- */
- boolean scrollTo(View v);
-
- /**
- * Like {@link #scrollTo(View)}, but keeps the scroll locked until the user
- * scrolls, or {@param v} loses focus or is detached.
- */
- void lockScrollTo(View v);
-
- /**
- * Request that the view does not dismiss for the current touch.
- */
- void requestDisallowDismiss();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index c060b08..195607d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -135,7 +135,7 @@
for (int i = 0; i < childCount; i++) {
ExpandableView child = algorithmState.visibleChildren.get(i);
ExpandableViewState state = resultState.getViewStateForView(child);
- if (!child.mustStayOnScreen()) {
+ if (!child.mustStayOnScreen() || state.headsUpIsVisible) {
previousNotificationEnd = Math.max(drawStart, previousNotificationEnd);
previousNotificationStart = Math.max(drawStart, previousNotificationStart);
}
@@ -378,6 +378,13 @@
boolean isEmptyShadeView = child instanceof EmptyShadeView;
childViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
+ float inset = ambientState.getTopPadding() + ambientState.getStackTranslation();
+ if (child.mustStayOnScreen() && childViewState.yTranslation >= 0) {
+ // Even if we're not scrolled away we're in view and we're also not in the
+ // shelf. We can relax the constraints and let us scroll off the top!
+ float end = childViewState.yTranslation + childViewState.height + inset;
+ childViewState.headsUpIsVisible = end < ambientState.getMaxHeadsUpTranslation();
+ }
if (isDismissView) {
childViewState.yTranslation = Math.min(childViewState.yTranslation,
ambientState.getInnerHeight() - childHeight);
@@ -396,8 +403,7 @@
Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
}
- childViewState.yTranslation += ambientState.getTopPadding()
- + ambientState.getStackTranslation();
+ childViewState.yTranslation += inset;
return currentYPosition;
}
@@ -420,19 +426,21 @@
break;
}
ExpandableViewState childState = resultState.getViewStateForView(row);
- if (topHeadsUpEntry == null) {
+ if (topHeadsUpEntry == null && row.mustStayOnScreen() && !childState.headsUpIsVisible) {
topHeadsUpEntry = row;
childState.location = ExpandableViewState.LOCATION_FIRST_HUN;
}
boolean isTopEntry = topHeadsUpEntry == row;
float unmodifiedEndLocation = childState.yTranslation + childState.height;
if (mIsExpanded) {
- // Ensure that the heads up is always visible even when scrolled off
- clampHunToTop(ambientState, row, childState);
- if (i == 0 && ambientState.isAboveShelf(row)) {
- // the first hun can't get off screen.
- clampHunToMaxTranslation(ambientState, row, childState);
- childState.hidden = false;
+ if (row.mustStayOnScreen() && !childState.headsUpIsVisible) {
+ // Ensure that the heads up is always visible even when scrolled off
+ clampHunToTop(ambientState, row, childState);
+ if (i == 0 && ambientState.isAboveShelf(row)) {
+ // the first hun can't get off screen.
+ clampHunToMaxTranslation(ambientState, row, childState);
+ childState.hidden = false;
+ }
}
}
if (row.isPinned()) {
@@ -493,6 +501,7 @@
if (childViewState.yTranslation >= shelfStart) {
childViewState.hidden = true;
childViewState.inShelf = true;
+ childViewState.headsUpIsVisible = false;
}
if (!ambientState.isShadeExpanded()) {
childViewState.height = (int) (mStatusBarHeight - childViewState.yTranslation);
@@ -531,7 +540,8 @@
ExpandableViewState childViewState = resultState.getViewStateForView(child);
int zDistanceBetweenElements = ambientState.getZDistanceBetweenElements();
float baseZ = ambientState.getBaseZHeight();
- if (child.mustStayOnScreen() && !ambientState.isDozingAndNotPulsing(child)
+ if (child.mustStayOnScreen() && !childViewState.headsUpIsVisible
+ && !ambientState.isDozingAndNotPulsing(child)
&& childViewState.yTranslation < ambientState.getTopPadding()
+ ambientState.getStackTranslation()) {
if (childrenOnTop != 0.0f) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index e3c746b..588b758 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -84,6 +84,7 @@
viewState.scaleX = view.getScaleX();
viewState.scaleY = view.getScaleY();
viewState.inShelf = false;
+ viewState.headsUpIsVisible = false;
}
public ExpandableViewState getViewStateForView(View requestedView) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
index 27b730cd..682b849 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
@@ -21,7 +21,6 @@
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
-import android.app.Notification;
import android.util.Property;
import android.view.View;
import android.view.animation.Interpolator;
@@ -29,7 +28,7 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.NotificationShelf;
+import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -64,8 +63,8 @@
private static final int TAG_START_TRANSLATION_Z = R.id.translation_z_animator_start_value_tag;
private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag;
- private static final PropertyAnimator.AnimatableProperty SCALE_X_PROPERTY
- = new PropertyAnimator.AnimatableProperty() {
+ private static final AnimatableProperty SCALE_X_PROPERTY
+ = new AnimatableProperty() {
@Override
public int getAnimationStartTag() {
@@ -88,8 +87,8 @@
}
};
- private static final PropertyAnimator.AnimatableProperty SCALE_Y_PROPERTY
- = new PropertyAnimator.AnimatableProperty() {
+ private static final AnimatableProperty SCALE_Y_PROPERTY
+ = new AnimatableProperty() {
@Override
public int getAnimationStartTag() {
@@ -251,7 +250,7 @@
return getChildTag(view, tag) != null;
}
- public static boolean isAnimating(View view, PropertyAnimator.AnimatableProperty property) {
+ public static boolean isAnimating(View view, AnimatableProperty property) {
return getChildTag(view, property.getAnimatorTag()) != null;
}
@@ -403,7 +402,7 @@
startZTranslationAnimation(view, NO_NEW_ANIMATIONS);
}
- private void updateAnimation(View view, PropertyAnimator.AnimatableProperty property,
+ private void updateAnimation(View view, AnimatableProperty property,
float endValue) {
PropertyAnimator.startAnimation(view, property, endValue, NO_NEW_ANIMATIONS);
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index b08b26d..2754026 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -49,7 +49,6 @@
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
-import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.qs.tiles.DndTile;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 0d41e20..3e70980 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -30,7 +30,6 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.ColorStateList;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
@@ -67,8 +66,6 @@
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
-import com.android.systemui.HardwareUiLayout;
-import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.plugins.VolumeDialog;
import com.android.systemui.plugins.VolumeDialogController;
@@ -97,11 +94,12 @@
private final VolumeDialogController mController;
private Window mWindow;
- private HardwareUiLayout mHardwareLayout;
private CustomDialog mDialog;
private ViewGroup mDialogView;
private ViewGroup mDialogRowsView;
private ViewGroup mDialogContentView;
+ private ImageButton mRingerIcon;
+ private TextView mRingerStatus;
private final List<VolumeRow> mRows = new ArrayList<>();
private ConfigurableTexts mConfigurableTexts;
private final SparseBooleanArray mDynamic = new SparseBooleanArray();
@@ -111,6 +109,7 @@
private final Accessibility mAccessibility = new Accessibility();
private final ColorStateList mActiveSliderTint;
private final ColorStateList mInactiveSliderTint;
+ private VolumeUiLayout mHardwareLayout;
private boolean mShowing;
private boolean mShowA11yStream;
@@ -160,17 +159,34 @@
mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
- mWindow.addFlags(
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
+ mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
+ mWindow.setTitle(VolumeDialogImpl.class.getSimpleName());
mWindow.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
mWindow.setWindowAnimations(com.android.internal.R.style.Animation_Toast);
mDialog.setContentView(R.layout.volume_dialog);
- mDialogView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog);
+ mDialog.setOnShowListener(new DialogInterface.OnShowListener() {
+ @Override
+ public void onShow(DialogInterface dialog) {
+ mDialogView.setTranslationY(-mDialogView.getHeight());
+ mDialogView.setAlpha(0);
+ mDialogView.animate()
+ .alpha(1)
+ .translationY(0)
+ .setDuration(300)
+ .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator())
+ .withEndAction(() -> {
+ mWindow.getDecorView().requestAccessibilityFocus();
+ })
+ .start();
+ }
+ });
+ mDialogView = mDialog.findViewById(R.id.volume_dialog);
mDialogView.setOnHoverListener(new View.OnHoverListener() {
@Override
public boolean onHover(View v, MotionEvent event) {
@@ -181,18 +197,20 @@
return true;
}
});
- mHardwareLayout = HardwareUiLayout.get(mDialogView);
+ mHardwareLayout = VolumeUiLayout.get(mDialogView);
mHardwareLayout.setOutsideTouchListener(view -> dismiss(DISMISS_REASON_TOUCH_OUTSIDE));
mDialogContentView = mDialog.findViewById(R.id.volume_dialog_content);
mDialogRowsView = mDialogContentView.findViewById(R.id.volume_dialog_rows);
+ mRingerIcon = mDialogContentView.findViewById(R.id.ringer_icon);
+ mRingerStatus = mDialogContentView.findViewById(R.id.ringer_status);
if (mRows.isEmpty()) {
addRow(AudioManager.STREAM_MUSIC,
R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true);
if (!AudioSystem.isSingleVolume(mContext)) {
addRow(AudioManager.STREAM_RING,
- R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true);
+ R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, false);
addRow(AudioManager.STREAM_ALARM,
R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, false);
addRow(AudioManager.STREAM_VOICE_CALL,
@@ -208,6 +226,7 @@
addExistingRows();
}
updateRowsH(getActiveRow());
+ initRingerH();
}
private ColorStateList loadColorStateList(int colorResId) {
@@ -374,6 +393,30 @@
}
}
+ public void initRingerH() {
+ mRingerIcon.setOnClickListener(v -> {
+ Events.writeEvent(mContext, Events.EVENT_ICON_CLICK, AudioManager.STREAM_RING,
+ mRingerIcon.getTag());
+ final StreamState ss = mState.states.get(AudioManager.STREAM_RING);
+ final boolean hasVibrator = mController.hasVibrator();
+ if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) {
+ if (hasVibrator) {
+ mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, false);
+ } else {
+ final boolean wasZero = ss.level == 0;
+ mController.setStreamVolume(AudioManager.STREAM_RING, wasZero ? 1 : 0);
+ }
+ } else {
+ mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false);
+ if (ss.level == 0) {
+ mController.setStreamVolume(AudioManager.STREAM_RING, 1);
+ }
+ }
+ updateRingerH();
+ });
+ updateRingerH();
+ }
+
public void show(int reason) {
mHandler.obtainMessage(H.SHOW, reason, 0).sendToTarget();
}
@@ -389,27 +432,12 @@
rescheduleTimeoutH();
if (mShowing) return;
mShowing = true;
- mHardwareLayout.setTranslationX(getAnimTranslation());
- mHardwareLayout.setAlpha(0);
- mHardwareLayout.animate()
- .alpha(1)
- .translationX(0)
- .setDuration(300)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .withEndAction(() -> {
- mDialog.show();
- mWindow.getDecorView().requestAccessibilityFocus();
- })
- .start();
+
+ mDialog.show();
Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
mController.notifyVisible(true);
}
- private float getAnimTranslation() {
- return mContext.getResources().getDimension(
- R.dimen.volume_dialog_panel_width) / 2;
- }
-
protected void rescheduleTimeoutH() {
mHandler.removeMessages(H.DISMISS);
final int timeout = computeTimeoutH();
@@ -423,7 +451,6 @@
if (mAccessibility.mFeedbackEnabled) return 20000;
if (mHovering) return 16000;
if (mSafetyWarning != null) return 5000;
- if (mActiveStream == AudioManager.STREAM_MUSIC) return 1500;
return 3000;
}
@@ -431,16 +458,22 @@
mHandler.removeMessages(H.DISMISS);
mHandler.removeMessages(H.SHOW);
if (!mShowing) return;
+ mDialogView.animate().cancel();
mShowing = false;
- mHardwareLayout.setTranslationX(0);
- mHardwareLayout.setAlpha(1);
- mHardwareLayout.animate()
+
+ mDialogView.setTranslationY(0);
+ mDialogView.setAlpha(1);
+ mDialogView.animate()
.alpha(0)
- .translationX(getAnimTranslation())
- .setDuration(300)
- .withEndAction(() -> mDialog.dismiss())
+ .translationY(-mDialogView.getHeight())
+ .setDuration(250)
.setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator())
+ .withEndAction(() -> mHandler.postDelayed(() -> {
+ if (D.BUG) Log.d(TAG, "mDialog.dismiss()");
+ mDialog.dismiss();
+ }, 50))
.start();
+
if (mAccessibilityMgr.isEnabled()) {
AccessibilityEvent event =
AccessibilityEvent.obtain(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
@@ -493,6 +526,53 @@
}
}
+ protected void updateRingerH() {
+ if (mState != null) {
+ final StreamState ss = mState.states.get(AudioManager.STREAM_RING);
+ switch (mState.ringerModeInternal) {
+ case AudioManager.RINGER_MODE_VIBRATE:
+ mRingerStatus.setText(R.string.volume_ringer_status_vibrate);
+ mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
+ mRingerIcon.setTag(Events.ICON_STATE_VIBRATE);
+ break;
+ case AudioManager.RINGER_MODE_SILENT:
+ mRingerStatus.setText(R.string.volume_ringer_status_silent);
+ mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
+ mRingerIcon.setContentDescription(mContext.getString(
+ R.string.volume_stream_content_description_unmute,
+ getStreamLabelH(ss)));
+ mRingerIcon.setTag(Events.ICON_STATE_MUTE);
+ break;
+ case AudioManager.RINGER_MODE_NORMAL:
+ default:
+ boolean muted = (mAutomute && ss.level == 0) || ss.muted ? true : false;
+ if (muted) {
+ mRingerStatus.setText(R.string.volume_ringer_status_silent);
+ mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
+ mRingerIcon.setContentDescription(mContext.getString(
+ R.string.volume_stream_content_description_unmute,
+ getStreamLabelH(ss)));
+ mRingerIcon.setTag(Events.ICON_STATE_MUTE);
+ } else {
+ mRingerStatus.setText(R.string.volume_ringer_status_normal);
+ mRingerIcon.setImageResource(R.drawable.ic_volume_ringer);
+ if (mController.hasVibrator()) {
+ mRingerIcon.setContentDescription(mContext.getString(
+ mShowA11yStream
+ ? R.string.volume_stream_content_description_vibrate_a11y
+ : R.string.volume_stream_content_description_vibrate,
+ getStreamLabelH(ss)));
+
+ } else {
+ mRingerIcon.setContentDescription(getStreamLabelH(ss));
+ }
+ mRingerIcon.setTag(Events.ICON_STATE_UNMUTE);
+ }
+ break;
+ }
+ }
+ }
+
private void trimObsoleteH() {
if (D.BUG) Log.d(TAG, "trimObsoleteH");
for (int i = mRows.size() - 1; i >= 0; i--) {
@@ -529,6 +609,7 @@
for (VolumeRow row : mRows) {
updateVolumeRowH(row);
}
+ updateRingerH();
}
private void updateVolumeRowH(VolumeRow row) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
new file mode 100644
index 0000000..49ac9b6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.volume;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
+
+public class VolumeUiLayout extends FrameLayout {
+
+ public VolumeUiLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsListener);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsListener);
+ }
+
+ @Override
+ public ViewOutlineProvider getOutlineProvider() {
+ return super.getOutlineProvider();
+ }
+
+ public void setOutsideTouchListener(OnClickListener onClickListener) {
+ requestLayout();
+ setOnClickListener(onClickListener);
+ setClickable(true);
+ setFocusable(true);
+ }
+
+ public static VolumeUiLayout get(View v) {
+ if (v instanceof VolumeUiLayout) return (VolumeUiLayout) v;
+ if (v.getParent() instanceof View) {
+ return get((View) v.getParent());
+ }
+ return null;
+ }
+
+ private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> {
+ inoutInfo.setTouchableInsets(
+ ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/car/CarVolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/car/CarVolumeDialogController.java
index d28e42e..474085c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/car/CarVolumeDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/car/CarVolumeDialogController.java
@@ -29,6 +29,8 @@
/**
* A volume dialog controller for the automotive use case.
+ * TODO(hwwang): consider removing this class since it's coupled with stream_type and we are
+ * moving to use AudioAttributes usage for volume control in a car.
*
* {@link android.car.media.CarAudioManager} is the source of truth to get the stream volumes.
* And volume changes should be sent to the car's audio module instead of the android's audio mixer.
@@ -70,7 +72,7 @@
return;
}
try {
- mCarAudioManager.setStreamVolume(stream, level, flag);
+ mCarAudioManager.setUsageVolume(stream, level, flag);
} catch (CarNotConnectedException e) {
Log.e(TAG, "Car is not connected", e);
}
@@ -84,7 +86,7 @@
}
try {
- return mCarAudioManager.getStreamVolume(stream);
+ return mCarAudioManager.getUsageVolume(stream);
} catch (CarNotConnectedException e) {
Log.e(TAG, "Car is not connected", e);
return 0;
@@ -99,7 +101,7 @@
}
try {
- return mCarAudioManager.getStreamMaxVolume(stream);
+ return mCarAudioManager.getUsageMaxVolume(stream);
} catch (CarNotConnectedException e) {
Log.e(TAG, "Car is not connected", e);
return 0;
@@ -114,7 +116,7 @@
}
try {
- return mCarAudioManager.getStreamMinVolume(stream);
+ return mCarAudioManager.getUsageMinVolume(stream);
} catch (CarNotConnectedException e) {
Log.e(TAG, "Car is not connected", e);
return 0;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
index b0c9f328..1c104cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
@@ -19,12 +19,13 @@
import android.annotation.NonNull;
import android.app.PendingIntent;
+import com.android.systemui.util.wakelock.WakeLock;
+
/**
* A rudimentary fake for DozeHost.
*/
class DozeHostFake implements DozeHost {
Callback callback;
- boolean pulseAborted;
boolean pulseExtended;
boolean animateWakeup;
boolean dozing;
@@ -92,11 +93,6 @@
}
@Override
- public void abortPulsing() {
- pulseAborted = true;
- }
-
- @Override
public void extendPulse() {
pulseExtended = true;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 004ff29..1c9c794 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -49,6 +49,7 @@
import com.android.systemui.qs.QSTileHost;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
@@ -108,6 +109,7 @@
}
@Test
+ @Ignore("flaky")
public void testStaleTimeout() throws InterruptedException {
when(mTile.getStaleTimeout()).thenReturn(5l);
clearInvocations(mTile);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java
index 6e59d10..2ff86c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java
@@ -39,9 +39,8 @@
private ExpandableNotificationRow mRow;
@Before
- @UiThreadTest
- public void setUp() {
- mRow = new ExpandableNotificationRow(mContext, null);
+ public void setUp() throws Exception {
+ mRow = new NotificationTestHelper(mContext).createRow();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
new file mode 100644
index 0000000..6ecfe3e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashSet;
+import java.util.Set;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class NotificationListenerTest extends SysuiTestCase {
+ private static final String TEST_PACKAGE_NAME = "test";
+ private static final int TEST_UID = 0;
+
+ private NotificationPresenter mPresenter;
+ private Handler mHandler;
+ private NotificationListener mListener;
+ private StatusBarNotification mSbn;
+ private NotificationListenerService.RankingMap mRanking;
+ private Set<String> mKeysKeptForRemoteInput;
+ private NotificationData mNotificationData;
+
+ @Before
+ public void setUp() {
+ mHandler = new Handler(Looper.getMainLooper());
+ mPresenter = mock(NotificationPresenter.class);
+ mNotificationData = mock(NotificationData.class);
+ mRanking = mock(NotificationListenerService.RankingMap.class);
+ mKeysKeptForRemoteInput = new HashSet<>();
+
+ when(mPresenter.getHandler()).thenReturn(mHandler);
+ when(mPresenter.getNotificationData()).thenReturn(mNotificationData);
+ when(mPresenter.getKeysKeptForRemoteInput()).thenReturn(mKeysKeptForRemoteInput);
+
+ mListener = new NotificationListener(mPresenter, mContext);
+ mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
+ new Notification(), UserHandle.CURRENT, null, 0);
+ }
+
+ @Test
+ public void testNotificationAddCallsAddNotification() {
+ mListener.onNotificationPosted(mSbn, mRanking);
+ waitForIdleSync(mHandler);
+ verify(mPresenter).addNotification(mSbn, mRanking);
+ }
+
+ @Test
+ public void testPostNotificationRemovesKeyKeptForRemoteInput() {
+ mKeysKeptForRemoteInput.add(mSbn.getKey());
+ mListener.onNotificationPosted(mSbn, mRanking);
+ waitForIdleSync(mHandler);
+ assertTrue(mKeysKeptForRemoteInput.isEmpty());
+ }
+
+ @Test
+ public void testNotificationUpdateCallsUpdateNotification() {
+ when(mNotificationData.get(mSbn.getKey())).thenReturn(new NotificationData.Entry(mSbn));
+ mListener.onNotificationPosted(mSbn, mRanking);
+ waitForIdleSync(mHandler);
+ verify(mPresenter).updateNotification(mSbn, mRanking);
+ }
+
+ @Test
+ public void testNotificationRemovalCallsRemoveNotification() {
+ mListener.onNotificationRemoved(mSbn, mRanking);
+ waitForIdleSync(mHandler);
+ verify(mPresenter).removeNotification(mSbn.getKey(), mRanking);
+ }
+
+ @Test
+ public void testRankingUpdateCallsNotificationRankingUpdate() {
+ mListener.onNotificationRankingUpdate(mRanking);
+ waitForIdleSync(mHandler);
+ // RankingMap may be modified by plugins.
+ verify(mPresenter).updateNotificationRanking(any());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
new file mode 100644
index 0000000..4045995
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static android.content.Intent.ACTION_DEVICE_LOCKED_CHANGED;
+import static android.content.Intent.ACTION_USER_SWITCHED;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+
+import com.google.android.collect.Lists;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
+ private NotificationPresenter mPresenter;
+ private TestNotificationLockscreenUserManager mLockscreenUserManager;
+ private DeviceProvisionedController mDeviceProvisionedController;
+ private int mCurrentUserId;
+ private Handler mHandler;
+ private UserManager mUserManager;
+
+ @Before
+ public void setUp() {
+ mUserManager = mock(UserManager.class);
+ mContext.addMockSystemService(UserManager.class, mUserManager);
+ mHandler = new Handler(Looper.getMainLooper());
+ mDependency.injectMockDependency(DeviceProvisionedController.class);
+ mDeviceProvisionedController = mDependency.get(DeviceProvisionedController.class);
+ mLockscreenUserManager = new TestNotificationLockscreenUserManager(mContext);
+ mDependency.injectTestDependency(NotificationLockscreenUserManager.class,
+ mLockscreenUserManager);
+
+ when(mUserManager.getProfiles(mCurrentUserId)).thenReturn(Lists.newArrayList(
+ new UserInfo(mCurrentUserId, "", 0), new UserInfo(mCurrentUserId + 1, "", 0)));
+
+ mPresenter = mock(NotificationPresenter.class);
+ when(mPresenter.getHandler()).thenReturn(mHandler);
+ mLockscreenUserManager.setUpWithPresenter(mPresenter);
+ mCurrentUserId = ActivityManager.getCurrentUser();
+ }
+
+ @Test
+ public void testLockScreenShowNotificationsChangeUpdatesNotifications() {
+ mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
+ verify(mPresenter, times(1)).updateNotifications();
+ }
+
+ @Test
+ public void testLockScreenShowNotificationsFalse() {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
+ mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
+ assertFalse(mLockscreenUserManager.shouldShowLockscreenNotifications());
+ }
+
+ @Test
+ public void testLockScreenShowNotificationsTrue() {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
+ mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
+ assertTrue(mLockscreenUserManager.shouldShowLockscreenNotifications());
+ }
+
+ @Test
+ public void testLockScreenAllowPrivateNotificationsTrue() {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1);
+ mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
+ assertTrue(mLockscreenUserManager.userAllowsPrivateNotificationsInPublic(mCurrentUserId));
+ }
+
+ @Test
+ public void testLockScreenAllowPrivateNotificationsFalse() {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
+ mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
+ assertFalse(mLockscreenUserManager.userAllowsPrivateNotificationsInPublic(mCurrentUserId));
+ }
+
+ @Test
+ public void testSettingsObserverUpdatesNotifications() {
+ when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
+ mLockscreenUserManager.getSettingsObserverForTest().onChange(false);
+ verify(mPresenter, times(1)).updateNotifications();
+ }
+
+ @Test
+ public void testActionDeviceLockedChangedWithDifferentUserIdCallsOnWorkChallengeChanged() {
+ Intent intent = new Intent()
+ .setAction(ACTION_DEVICE_LOCKED_CHANGED)
+ .putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId + 1);
+ mLockscreenUserManager.getAllUsersReceiverForTest().onReceive(mContext, intent);
+ verify(mPresenter, times(1)).onWorkChallengeChanged();
+ }
+
+ @Test
+ public void testActionUserSwitchedCallsOnUserSwitched() {
+ Intent intent = new Intent()
+ .setAction(ACTION_USER_SWITCHED)
+ .putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId + 1);
+ mLockscreenUserManager.getBaseBroadcastReceiverForTest().onReceive(mContext, intent);
+ verify(mPresenter, times(1)).onUserSwitched(mCurrentUserId + 1);
+ }
+
+ @Test
+ public void testIsLockscreenPublicMode() {
+ assertFalse(mLockscreenUserManager.isLockscreenPublicMode(mCurrentUserId));
+ mLockscreenUserManager.setLockscreenPublicMode(true, mCurrentUserId);
+ assertTrue(mLockscreenUserManager.isLockscreenPublicMode(mCurrentUserId));
+ }
+
+ private class TestNotificationLockscreenUserManager extends NotificationLockscreenUserManager {
+ public TestNotificationLockscreenUserManager(Context context) {
+ super(context);
+ }
+
+ public BroadcastReceiver getAllUsersReceiverForTest() {
+ return mAllUsersReceiver;
+ }
+
+ public BroadcastReceiver getBaseBroadcastReceiverForTest() {
+ return mBaseBroadcastReceiver;
+ }
+
+ public ContentObserver getLockscreenSettingsObserverForTest() {
+ return mLockscreenSettingsObserver;
+ }
+
+ public ContentObserver getSettingsObserverForTest() {
+ return mSettingsObserver;
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationSnoozeTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationSnoozeTest.java
index 6b31c96..756bb1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationSnoozeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationSnoozeTest.java
@@ -62,57 +62,6 @@
}
@Test
- public void testParseIntArrayNull() throws Exception {
- when(mMockParser.getString(anyString(), isNull())).thenReturn(null);
- mNotificationSnooze.setKeyValueListParser(mMockParser);
-
- int[] result = mNotificationSnooze.parseIntArray("foo", RES_OPTIONS);
- assertEquals(RES_OPTIONS, result);
- }
-
- @Test
- public void testParseIntArrayLeadingSep() throws Exception {
- when(mMockParser.getString(anyString(), isNull())).thenReturn(":4:5:6");
- mNotificationSnooze.setKeyValueListParser(mMockParser);
-
- int[] result = mNotificationSnooze.parseIntArray("foo", RES_OPTIONS);
- assertEquals(RES_OPTIONS, result);
- }
-
- @Test
- public void testParseIntArrayEmptyItem() throws Exception {
- when(mMockParser.getString(anyString(), isNull())).thenReturn("4::6");
- mNotificationSnooze.setKeyValueListParser(mMockParser);
-
- int[] result = mNotificationSnooze.parseIntArray("foo", RES_OPTIONS);
- assertEquals(RES_OPTIONS, result);
- }
-
- @Test
- public void testParseIntArrayTrailingSep() throws Exception {
- when(mMockParser.getString(anyString(), isNull())).thenReturn("4:5:6:");
- mNotificationSnooze.setKeyValueListParser(mMockParser);
-
- int[] result = mNotificationSnooze.parseIntArray("foo", RES_OPTIONS);
- assertEquals(3, result.length);
- assertEquals(4, result[0]); // respect order
- assertEquals(5, result[1]);
- assertEquals(6, result[2]);
- }
-
- @Test
- public void testParseIntArrayGoodData() throws Exception {
- when(mMockParser.getString(anyString(), isNull())).thenReturn("4:5:6");
- mNotificationSnooze.setKeyValueListParser(mMockParser);
-
- int[] result = mNotificationSnooze.parseIntArray("foo", RES_OPTIONS);
- assertEquals(3, result.length);
- assertEquals(4, result[0]); // respect order
- assertEquals(5, result[1]);
- assertEquals(6, result[2]);
- }
-
- @Test
public void testGetOptionsWithNoConfig() throws Exception {
ArrayList<SnoozeOption> result = mNotificationSnooze.getDefaultSnoozeOptions();
assertEquals(3, result.size());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java
index 4c3bf10..42dad11 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java
@@ -86,9 +86,9 @@
@Test
public void testSetViewAlpha_propagatesToDrawable() {
- float alpha = 0.5f;
+ final float alpha = 0.5f;
mView.setViewAlpha(alpha);
- assertEquals(mView.getViewAlpha(), alpha);
+ assertEquals("View alpha did not propagate to drawable", alpha, mView.getViewAlpha());
}
@Test
@@ -97,7 +97,7 @@
Canvas canvas = mock(Canvas.class);
mView.onDraw(canvas);
// One time for each rect side
- verify(canvas, times(4)).clipRect(anyInt(), anyInt(), anyInt(), anyInt());
+ verify(canvas, times(8)).clipRect(anyInt(), anyInt(), anyInt(), anyInt());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
index eaa073c..a153140 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
@@ -35,7 +35,6 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.stack.AnimationFilter;
import com.android.systemui.statusbar.stack.AnimationProperties;
import com.android.systemui.statusbar.stack.ViewState;
@@ -63,8 +62,8 @@
return mValue;
}
};
- private PropertyAnimator.AnimatableProperty mProperty
- = new PropertyAnimator.AnimatableProperty() {
+ private AnimatableProperty mProperty
+ = new AnimatableProperty() {
@Override
public int getAnimationStartTag() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
new file mode 100644
index 0000000..ca2f713
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.os.Debug;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.doze.DozeHost;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class DozeScrimControllerTest extends SysuiTestCase {
+
+ private ScrimController mScrimController;
+ private DozeScrimController mDozeScrimController;
+
+ @Before
+ public void setup() {
+ mScrimController = mock(ScrimController.class);
+ // Make sure callbacks will be invoked to complete the lifecycle.
+ doAnswer(invocationOnMock -> {
+ ScrimController.Callback callback = invocationOnMock.getArgument(1);
+ callback.onStart();
+ callback.onDisplayBlanked();
+ callback.onFinished();
+ return null;
+ }).when(mScrimController).transitionTo(any(ScrimState.class),
+ any(ScrimController.Callback.class));
+
+ mDozeScrimController = new DozeScrimController(mScrimController, getContext());
+ mDozeScrimController.setDozing(true);
+ }
+
+ @Test
+ public void changesScrimControllerState() {
+ mDozeScrimController.pulse(mock(DozeHost.PulseCallback.class), 0);
+ verify(mScrimController).transitionTo(eq(ScrimState.PULSING),
+ any(ScrimController.Callback.class));
+ }
+
+ @Test
+ public void callsPulseCallback() {
+ DozeHost.PulseCallback callback = mock(DozeHost.PulseCallback.class);
+ mDozeScrimController.pulse(callback, 0);
+
+ verify(callback).onPulseStarted();
+ mDozeScrimController.pulseOutNow();
+ verify(callback).onPulseFinished();
+ }
+
+ @Test
+ public void secondPulseIsSuppressed() {
+ DozeHost.PulseCallback callback1 = mock(DozeHost.PulseCallback.class);
+ DozeHost.PulseCallback callback2 = mock(DozeHost.PulseCallback.class);
+ mDozeScrimController.pulse(callback1, 0);
+ mDozeScrimController.pulse(callback2, 0);
+
+ verify(callback1, never()).onPulseFinished();
+ verify(callback2).onPulseFinished();
+ }
+
+ @Test
+ public void suppressesPulseIfNotDozing() {
+ mDozeScrimController.setDozing(false);
+ DozeHost.PulseCallback callback = mock(DozeHost.PulseCallback.class);
+ mDozeScrimController.pulse(callback, 0);
+
+ verify(callback).onPulseFinished();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
new file mode 100644
index 0000000..b9f695b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.animation.Animator;
+import android.graphics.Color;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.View;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.ScrimView;
+import com.android.systemui.util.wakelock.WakeLock;
+import com.android.systemui.utils.os.FakeHandler;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.function.Consumer;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class ScrimControllerTest extends SysuiTestCase {
+
+ private SynchronousScrimController mScrimController;
+ private ScrimView mScrimBehind;
+ private ScrimView mScrimInFront;
+ private View mHeadsUpScrim;
+ private Consumer<Boolean> mScrimVisibilityCallback;
+ private Boolean mScrimVisibile;
+ private LightBarController mLightBarController;
+ private DozeParameters mDozeParamenters;
+ private WakeLock mWakeLock;
+ private boolean mAlwaysOnEnabled;
+
+ @Before
+ public void setup() {
+ mLightBarController = mock(LightBarController.class);
+ mScrimBehind = new ScrimView(getContext());
+ mScrimInFront = new ScrimView(getContext());
+ mHeadsUpScrim = mock(View.class);
+ mWakeLock = mock(WakeLock.class);
+ mAlwaysOnEnabled = true;
+ mScrimVisibilityCallback = (Boolean visible) -> mScrimVisibile = visible;
+ mDozeParamenters = mock(DozeParameters.class);
+ when(mDozeParamenters.getAlwaysOn()).thenAnswer(invocation -> mAlwaysOnEnabled);
+ mScrimController = new SynchronousScrimController(mLightBarController, mScrimBehind,
+ mScrimInFront, mHeadsUpScrim, mScrimVisibilityCallback, mDozeParamenters);
+ }
+
+ @Test
+ public void initialState() {
+ Assert.assertEquals("ScrimController should start initialized",
+ mScrimController.getState(), ScrimState.UNINITIALIZED);
+ }
+
+ @Test
+ public void transitionToKeyguard() {
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ mScrimController.finishAnimationsImmediately();
+ // Front scrim should be transparent
+ // Back scrim should be visible without tint
+ assertScrimVisibility(false /* front */, true /* behind */);
+ assertScrimTint(mScrimBehind, false /* tinted */);
+ }
+
+ @Test
+ public void transitionToAod() {
+ mScrimController.transitionTo(ScrimState.AOD);
+ mScrimController.finishAnimationsImmediately();
+ // Front scrim should be transparent
+ // Back scrim should be visible with tint
+ assertScrimVisibility(false /* front */, true /* behind */);
+ assertScrimTint(mScrimBehind, true /* tinted */);
+ assertScrimTint(mScrimInFront, true /* tinted */);
+ }
+
+ @Test
+ public void transitionToPulsing() {
+ mScrimController.transitionTo(ScrimState.PULSING);
+ mScrimController.finishAnimationsImmediately();
+ // Front scrim should be transparent
+ // Back scrim should be visible with tint
+ // Pulse callback should have been invoked
+ assertScrimVisibility(false /* front */, true /* behind */);
+ assertScrimTint(mScrimBehind, true /* tinted */);
+ }
+
+ @Test
+ public void transitionToBouncer() {
+ mScrimController.transitionTo(ScrimState.BOUNCER);
+ mScrimController.finishAnimationsImmediately();
+ // Front scrim should be transparent
+ // Back scrim should be visible without tint
+ assertScrimVisibility(true /* front */, true /* behind */);
+ assertScrimTint(mScrimBehind, false /* tinted */);
+ }
+
+ @Test
+ public void transitionToUnlocked() {
+ mScrimController.transitionTo(ScrimState.UNLOCKED);
+ mScrimController.finishAnimationsImmediately();
+ // Front scrim should be transparent
+ // Back scrim should be transparent
+ assertScrimVisibility(false /* front */, false /* behind */);
+ assertScrimTint(mScrimBehind, false /* tinted */);
+ assertScrimTint(mScrimInFront, false /* tinted */);
+
+ // Back scrim should be visible after start dragging
+ mScrimController.setPanelExpansion(0.5f);
+ assertScrimVisibility(false /* front */, true /* behind */);
+ }
+
+ @Test
+ public void transitionToUnlockedFromAod() {
+ // Simulate unlock with fingerprint
+ mScrimController.transitionTo(ScrimState.AOD);
+ mScrimController.finishAnimationsImmediately();
+ mScrimController.transitionTo(ScrimState.UNLOCKED);
+ // Immediately tinted after the transition starts
+ assertScrimTint(mScrimInFront, true /* tinted */);
+ assertScrimTint(mScrimBehind, true /* tinted */);
+ mScrimController.finishAnimationsImmediately();
+ // Front scrim should be transparent
+ // Back scrim should be transparent
+ // Neither scrims should be tinted anymore after the animation.
+ assertScrimVisibility(false /* front */, false /* behind */);
+ assertScrimTint(mScrimInFront, false /* tinted */);
+ assertScrimTint(mScrimBehind, false /* tinted */);
+ }
+
+ @Test
+ public void scrimBlanksBeforeLeavingAoD() {
+ // Simulate unlock with fingerprint
+ mScrimController.transitionTo(ScrimState.AOD);
+ mScrimController.finishAnimationsImmediately();
+ mScrimController.transitionTo(ScrimState.UNLOCKED,
+ new ScrimController.Callback() {
+ @Override
+ public void onDisplayBlanked() {
+ // Front scrim should be black in the middle of the transition
+ Assert.assertTrue("Scrim should be visible during transition. Alpha: "
+ + mScrimInFront.getViewAlpha(), mScrimInFront.getViewAlpha() > 0);
+ assertScrimTint(mScrimInFront, true /* tinted */);
+ Assert.assertTrue("Scrim should be visible during transition.",
+ mScrimVisibile);
+ }
+ });
+ mScrimController.finishAnimationsImmediately();
+ }
+
+ @Test
+ public void testScrimCallback() {
+ int[] callOrder = {0, 0, 0};
+ int[] currentCall = {0};
+ mScrimController.transitionTo(ScrimState.AOD, new ScrimController.Callback() {
+ @Override
+ public void onStart() {
+ callOrder[0] = ++currentCall[0];
+ }
+
+ @Override
+ public void onDisplayBlanked() {
+ callOrder[1] = ++currentCall[0];
+ }
+
+ @Override
+ public void onFinished() {
+ callOrder[2] = ++currentCall[0];
+ }
+ });
+ mScrimController.finishAnimationsImmediately();
+ Assert.assertEquals("onStart called in wrong order", 1, callOrder[0]);
+ Assert.assertEquals("onDisplayBlanked called in wrong order", 2, callOrder[1]);
+ Assert.assertEquals("onFinished called in wrong order", 3, callOrder[2]);
+ }
+
+ @Test
+ public void testScrimCallbacksWithoutAmbientDisplay() {
+ mAlwaysOnEnabled = false;
+ testScrimCallback();
+ }
+
+ @Test
+ public void testScrimCallbackCancelled() {
+ boolean[] cancelledCalled = {false};
+ mScrimController.transitionTo(ScrimState.AOD, new ScrimController.Callback() {
+ @Override
+ public void onCancelled() {
+ cancelledCalled[0] = true;
+ }
+ });
+ mScrimController.transitionTo(ScrimState.PULSING);
+ Assert.assertTrue("onCancelled should have been called", cancelledCalled[0]);
+ }
+
+ @Test
+ public void testHoldsWakeLock() {
+ mScrimController.transitionTo(ScrimState.AOD);
+ verify(mWakeLock, times(1)).acquire();
+ verify(mWakeLock, never()).release();
+ mScrimController.finishAnimationsImmediately();
+ verify(mWakeLock, times(1)).release();
+ }
+
+ private void assertScrimTint(ScrimView scrimView, boolean tinted) {
+ final boolean viewIsTinted = scrimView.getTint() != Color.TRANSPARENT;
+ final String name = scrimView == mScrimInFront ? "front" : "back";
+ Assert.assertEquals("Tint test failed at state " + mScrimController.getState()
+ +" with scrim: " + name + " and tint: " + Integer.toHexString(scrimView.getTint()),
+ tinted, viewIsTinted);
+ }
+
+ private void assertScrimVisibility(boolean inFront, boolean behind) {
+ Assert.assertEquals("Unexpected front scrim visibility. Alpha is "
+ + mScrimInFront.getViewAlpha(), inFront, mScrimInFront.getViewAlpha() > 0);
+ Assert.assertEquals("Unexpected back scrim visibility. Alpha is "
+ + mScrimBehind.getViewAlpha(), behind, mScrimBehind.getViewAlpha() > 0);
+ Assert.assertEquals("Invalid visibility.", inFront || behind, mScrimVisibile);
+ }
+
+ /**
+ * Special version of ScrimController where animations have 0 duration for test purposes.
+ */
+ private class SynchronousScrimController extends ScrimController {
+
+ private FakeHandler mHandler;
+
+ public SynchronousScrimController(LightBarController lightBarController,
+ ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim,
+ Consumer<Boolean> scrimVisibleListener, DozeParameters dozeParameters) {
+ super(lightBarController, scrimBehind, scrimInFront, headsUpScrim,
+ scrimVisibleListener, dozeParameters);
+ mHandler = new FakeHandler(Looper.myLooper());
+ }
+
+ public void finishAnimationsImmediately() {
+ boolean[] animationFinished = {false};
+ setOnAnimationFinished(()-> animationFinished[0] = true);
+
+ // Execute code that will trigger animations.
+ onPreDraw();
+
+ // Force finish screen blanking.
+ endAnimation(mScrimInFront, TAG_KEY_ANIM_BLANK);
+ mHandler.dispatchQueuedMessages();
+ // Force finish all animations.
+ endAnimation(mScrimBehind, TAG_KEY_ANIM);
+ endAnimation(mScrimInFront, TAG_KEY_ANIM);
+
+ if (!animationFinished[0]) {
+ throw new IllegalStateException("Animation never finished");
+ }
+ }
+
+ private void endAnimation(ScrimView scrimView, int tag) {
+ Animator animator = (Animator) scrimView.getTag(tag);
+ if (animator != null) {
+ animator.end();
+ }
+ }
+
+ @Override
+ protected Handler getHandler() {
+ return mHandler;
+ }
+
+ @Override
+ protected WakeLock createWakeLock() {
+ return mWakeLock;
+ }
+ }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 899e873..5ff90d91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -54,6 +54,7 @@
import android.testing.TestableLooper.MessageHandler;
import android.testing.TestableLooper.RunWithLooper;
import android.util.DisplayMetrics;
+import android.util.SparseArray;
import android.view.ViewGroup.LayoutParams;
import com.android.internal.logging.MetricsLogger;
@@ -71,6 +72,7 @@
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -102,6 +104,7 @@
PowerManager mPowerManager;
SystemServicesProxy mSystemServicesProxy;
NotificationPanelView mNotificationPanelView;
+ ScrimController mScrimController;
IStatusBarService mBarService;
ArrayList<Entry> mNotificationList;
private DisplayMetrics mDisplayMetrics = new DisplayMetrics();
@@ -129,6 +132,7 @@
mNotificationPanelView = mock(NotificationPanelView.class);
when(mNotificationPanelView.getLayoutParams()).thenReturn(new LayoutParams(0, 0));
mNotificationList = mock(ArrayList.class);
+ mScrimController = mock(ScrimController.class);
IPowerManager powerManagerService = mock(IPowerManager.class);
HandlerThread handlerThread = new HandlerThread("TestThread");
handlerThread.start();
@@ -141,7 +145,7 @@
mStatusBar = new TestableStatusBar(mStatusBarKeyguardViewManager, mUnlockMethodCache,
mKeyguardIndicationController, mStackScroller, mHeadsUpManager,
mNotificationData, mPowerManager, mSystemServicesProxy, mNotificationPanelView,
- mBarService);
+ mBarService, mScrimController);
mStatusBar.mContext = mContext;
mStatusBar.mComponents = mContext.getComponents();
doAnswer(invocation -> {
@@ -426,6 +430,7 @@
public void testLogHidden() {
try {
mStatusBar.handleVisibleToUserChanged(false);
+ waitForUiOffloadThread();
verify(mBarService, times(1)).onPanelHidden();
verify(mBarService, never()).onPanelRevealed(anyBoolean(), anyInt());
} catch (RemoteException e) {
@@ -443,7 +448,7 @@
try {
mStatusBar.handleVisibleToUserChanged(true);
-
+ waitForUiOffloadThread();
verify(mBarService, never()).onPanelHidden();
verify(mBarService, times(1)).onPanelRevealed(false, 1);
} catch (RemoteException e) {
@@ -462,7 +467,7 @@
try {
mStatusBar.handleVisibleToUserChanged(true);
-
+ waitForUiOffloadThread();
verify(mBarService, never()).onPanelHidden();
verify(mBarService, times(1)).onPanelRevealed(true, 5);
} catch (RemoteException e) {
@@ -481,7 +486,7 @@
try {
mStatusBar.handleVisibleToUserChanged(true);
-
+ waitForUiOffloadThread();
verify(mBarService, never()).onPanelHidden();
verify(mBarService, times(1)).onPanelRevealed(false, 5);
} catch (RemoteException e) {
@@ -524,15 +529,27 @@
mStatusBar.mState = StatusBarState.KEYGUARD;
mStatusBar.mDozeScrimController = mock(DozeScrimController.class);
mStatusBar.mNotificationIconAreaController = mock(NotificationIconAreaController.class);
+ mStatusBar.mLockscreenUserManager = mock(NotificationLockscreenUserManager.class);
+ when(mStatusBar.mLockscreenUserManager.getCurrentProfiles()).thenReturn(
+ new SparseArray<>());
mStatusBar.updateKeyguardState(false, false);
}
+ @Test
+ public void testFingerprintNotification_UpdatesScrims() {
+ mStatusBar.mStatusBarWindowManager = mock(StatusBarWindowManager.class);
+ mStatusBar.mFingerprintUnlockController = mock(FingerprintUnlockController.class);
+ mStatusBar.mDozeScrimController = mock(DozeScrimController.class);
+ mStatusBar.notifyFpAuthModeChanged();
+ verify(mScrimController).transitionTo(any(), any());
+ }
+
static class TestableStatusBar extends StatusBar {
public TestableStatusBar(StatusBarKeyguardViewManager man,
UnlockMethodCache unlock, KeyguardIndicationController key,
NotificationStackScrollLayout stack, HeadsUpManager hum, NotificationData nd,
PowerManager pm, SystemServicesProxy ssp, NotificationPanelView panelView,
- IStatusBarService barService) {
+ IStatusBarService barService, ScrimController scrimController) {
mStatusBarKeyguardViewManager = man;
mUnlockMethodCache = unlock;
mKeyguardIndicationController = key;
@@ -545,7 +562,7 @@
mNotificationPanel = panelView;
mBarService = barService;
mWakefulnessLifecycle = createAwakeWakefulnessLifecycle();
- mScrimController = mock(ScrimController.class);
+ mScrimController = scrimController;
}
private WakefulnessLifecycle createAwakeWakefulnessLifecycle() {
@@ -568,4 +585,4 @@
mUserSetup = userSetup;
}
}
-}
\ No newline at end of file
+}
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 1419e9a..3b796ca 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
@@ -15,6 +15,7 @@
import com.android.settingslib.net.DataUsageController;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -137,6 +138,22 @@
}
@Test
+ public void testAlwaysShowDataRatIcon() {
+ setupDefaultSignal();
+ when(mMockTm.getDataEnabled(mSubId)).thenReturn(false);
+ updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED,
+ TelephonyManager.NETWORK_TYPE_GSM);
+
+ // Switch to showing data RAT icon when data is disconnected
+ // and re-initialize the NetworkController.
+ mConfig.alwaysShowDataRatIcon = true;
+ mNetworkController.handleConfigurationChanged();
+
+ verifyDataIndicators(TelephonyIcons.ICON_G,
+ TelephonyIcons.QS_DATA_G);
+ }
+
+ @Test
public void test4gDataIconConfigChange() {
setupDefaultSignal();
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeRotationLockController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeRotationLockController.java
index d60fe78..be11024 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeRotationLockController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeRotationLockController.java
@@ -49,4 +49,9 @@
public void setRotationLocked(boolean locked) {
}
+
+ @Override
+ public void setRotationLockedAtAngle(boolean locked, int rotation) {
+
+ }
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 32af29d..ba6bb23 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4138,6 +4138,19 @@
// OS: O
FIELD_NOTIFICATION_GROUP_SUMMARY = 947;
+ // An app attempted to forge a different component name in the AssisStructure that would be
+ // passed to the autofill service.
+ // OS: O (security patch)
+ // Package: Real package of the app being autofilled
+ // Tag FIELD_AUTOFILL_SERVICE: Package of the autofill service that processed the request
+ // TAG FIELD_AUTOFILL_FORGED_COMPONENT_NAME: Component name being forged
+ AUTOFILL_FORGED_COMPONENT_ATTEMPT = 948;
+
+ // FIELD - The component that an app tried tro forged.
+ // Type: string
+ // OS: O (security patch)
+ FIELD_AUTOFILL_FORGED_COMPONENT_NAME = 949;
+
// ---- End O Constants, all O constants go above this line ----
// OPEN: Settings > System > Languages & input > Advanced > Lift to open camera
@@ -5013,8 +5026,48 @@
// OS: P
FIELD_SELECTION_WIDGET_VERSION = 1262;
- // ---- End P Constants, all P constants go above this line ----
+ // OPEN: Settings > Battery(version 2)
+ // CATEGORY: SETTINGS
+ // OS: P
+ FUELGAUGE_POWER_USAGE_SUMMARY_V2 = 1263;
+ // OPEN: Settings > Connected devices > Connection preferences
+ // CATEGORY: SETTINGS
+ // OS: P
+ CONNECTION_DEVICE_ADVANCED = 1264;
+
+ // OPEN: Settings > Security > Screen lock gear icon
+ // CATEGORY: SETTINGS
+ // OS: P
+ SCREEN_LOCK_SETTINGS = 1265;
+
+ // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Delete rule (trash can icon)
+ // CATEGORY: SETTINGS
+ // OS: P
+ NOTIFICATION_ZEN_MODE_DELETE_RULE_DIALOG = 1266;
+
+ // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Select rule ("Event") > Rule name > OK
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK = 1267;
+
+ // OPEN: Settings > Sound > Do Not Disturb > TURN ON NOW/TURN OFF NOW
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_ZEN_TOGGLE_DND_BUTTON = 1268;
+
+ // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Add rule > Event/Time
+ // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Select rule ("Event") > Rule name
+ // CATEGORY: SETTINGS
+ // OS: P
+ NOTIFICATION_ZEN_MODE_RULE_NAME_DIALOG = 1269;
+
+ // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Add rule
+ // CATEGORY: SETTINGS
+ // OS: P
+ NOTIFICATION_ZEN_MODE_RULE_SELECTION_DIALOG = 1270;
+
+ // ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 52f721b..75d080d 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -223,6 +223,9 @@
// Package: com.android.systemui
NOTE_TV_PIP = 1100;
+ // Extreme battery saver notifiaction.
+ NOTE_BATTERY_SAVER_WARNING = 1200;
+
// Notify the user that open Wi-Fi networks are available.
// Package: android
NOTE_NETWORK_AVAILABLE = 17303299;
diff --git a/services/Android.bp b/services/Android.bp
new file mode 100644
index 0000000..84c45fe
--- /dev/null
+++ b/services/Android.bp
@@ -0,0 +1,8 @@
+// native library
+// =============================================================
+
+cc_library_shared {
+ name: "libandroid_servers",
+ defaults: ["libservices.core-libs"],
+ whole_static_libs: ["libservices.core"],
+}
diff --git a/services/Android.mk b/services/Android.mk
index ed2ba1f..81d8181 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -52,23 +52,6 @@
include $(BUILD_JAVA_LIBRARY)
-# native library
-# =============================================================
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES :=
-LOCAL_SHARED_LIBRARIES :=
-
-# include all the jni subdirs to collect their sources
-include $(wildcard $(LOCAL_PATH)/*/jni/Android.mk)
-
-LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
-
-LOCAL_MODULE:= libandroid_servers
-
-include $(BUILD_SHARED_LIBRARY)
-
# =============================================================
ifeq (,$(ONE_SHOT_MAKEFILE))
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 3554448..0a21b9e 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -100,7 +100,8 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IntPair;
import com.android.server.LocalServices;
-import com.android.server.policy.AccessibilityShortcutController;
+import com.android.internal.accessibility.AccessibilityShortcutController;
+import com.android.internal.accessibility.AccessibilityShortcutController.ToggleableFrameworkFeatureInfo;
import com.android.server.wm.WindowManagerInternal;
import org.xmlpull.v1.XmlPullParserException;
@@ -1897,8 +1898,11 @@
if (userState.mServiceToEnableWithShortcut == null) {
return;
}
- boolean shortcutServiceIsInstalled = false;
- for (int i = 0; i < userState.mInstalledServices.size(); i++) {
+ boolean shortcutServiceIsInstalled =
+ AccessibilityShortcutController.getFrameworkShortcutFeaturesMap()
+ .containsKey(userState.mServiceToEnableWithShortcut);
+ for (int i = 0; !shortcutServiceIsInstalled && (i < userState.mInstalledServices.size());
+ i++) {
if (userState.mInstalledServices.get(i).getComponentName()
.equals(userState.mServiceToEnableWithShortcut)) {
shortcutServiceIsInstalled = true;
@@ -1909,7 +1913,8 @@
final long identity = Binder.clearCallingIdentity();
try {
Settings.Secure.putStringForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null, userState.mUserId);
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null,
+ userState.mUserId);
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 0, userState.mUserId);
@@ -2117,12 +2122,26 @@
throw new SecurityException(
"performAccessibilityShortcut requires the WRITE_SECURE_SETTINGS permission");
}
+ final Map<ComponentName, ToggleableFrameworkFeatureInfo> frameworkFeatureMap =
+ AccessibilityShortcutController.getFrameworkShortcutFeaturesMap();
synchronized(mLock) {
- UserState userState = getUserStateLocked(mCurrentUserId);
- ComponentName serviceName = userState.mServiceToEnableWithShortcut;
+ final UserState userState = getUserStateLocked(mCurrentUserId);
+ final ComponentName serviceName = userState.mServiceToEnableWithShortcut;
if (serviceName == null) {
return;
}
+ if (frameworkFeatureMap.containsKey(serviceName)) {
+ // Toggle the requested framework feature
+ ToggleableFrameworkFeatureInfo featureInfo = frameworkFeatureMap.get(serviceName);
+ SettingStringHelper setting = new SettingStringHelper(mContext.getContentResolver(),
+ featureInfo.getSettingKey(), mCurrentUserId);
+ // Assuming that the default state will be to have the feature off
+ if (!TextUtils.equals(featureInfo.getSettingOnValue(), setting.read())) {
+ setting.write(featureInfo.getSettingOnValue());
+ } else {
+ setting.write(featureInfo.getSettingOffValue());
+ }
+ }
final long identity = Binder.clearCallingIdentity();
try {
if (userState.mComponentNameToServiceMap.get(serviceName) == null) {
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 6c15438..b446209 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -2506,6 +2506,8 @@
info.widgetCategory = sa.getInt(
com.android.internal.R.styleable.AppWidgetProviderInfo_widgetCategory,
AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN);
+ info.widgetFeatures = sa.getInt(
+ com.android.internal.R.styleable.AppWidgetProviderInfo_widgetFeatures, 0);
sa.recycle();
} catch (IOException | PackageManager.NameNotFoundException | XmlPullParserException e) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 23e4f50..690c45b 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -52,6 +52,7 @@
import android.os.UserManagerInternal;
import android.provider.Settings;
import android.service.autofill.FillEventHistory;
+import android.service.autofill.UserData;
import android.util.LocalLog;
import android.util.Slog;
import android.util.SparseArray;
@@ -581,6 +582,49 @@
}
@Override
+ public UserData getUserData() throws RemoteException {
+ UserHandle user = getCallingUserHandle();
+ int uid = getCallingUid();
+
+ synchronized (mLock) {
+ AutofillManagerServiceImpl service = peekServiceForUserLocked(user.getIdentifier());
+ if (service != null) {
+ return service.getUserData(uid);
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public void setUserData(UserData userData) throws RemoteException {
+ UserHandle user = getCallingUserHandle();
+ int uid = getCallingUid();
+
+ synchronized (mLock) {
+ AutofillManagerServiceImpl service = peekServiceForUserLocked(user.getIdentifier());
+ if (service != null) {
+ service.setUserData(uid, userData);
+ }
+ }
+ }
+
+ @Override
+ public boolean isFieldClassificationEnabled() throws RemoteException {
+ UserHandle user = getCallingUserHandle();
+ int uid = getCallingUid();
+
+ synchronized (mLock) {
+ AutofillManagerServiceImpl service = peekServiceForUserLocked(user.getIdentifier());
+ if (service != null) {
+ return service.isFieldClassificationEnabled();
+ }
+ }
+
+ return false;
+ }
+
+ @Override
public boolean restoreSession(int sessionId, IBinder activityToken, IBinder appCallback)
throws RemoteException {
activityToken = Preconditions.checkNotNull(activityToken, "activityToken");
@@ -723,6 +767,7 @@
}
boolean oldDebug = sDebug;
+ final String prefix = " ";
try {
synchronized (mLock) {
oldDebug = sDebug;
@@ -731,6 +776,7 @@
pw.print("Verbose mode: "); pw.println(sVerbose);
pw.print("Disabled users: "); pw.println(mDisabledUsers);
pw.print("Max partitions per session: "); pw.println(sPartitionMaxCount);
+ pw.println("User data constraints: "); UserData.dumpConstraints(prefix, pw);
final int size = mServicesCache.size();
pw.print("Cached services: ");
if (size == 0) {
@@ -740,7 +786,7 @@
for (int i = 0; i < size; i++) {
pw.print("\nService at index "); pw.println(i);
final AutofillManagerServiceImpl impl = mServicesCache.valueAt(i);
- impl.dumpLocked(" ", pw);
+ impl.dumpLocked(prefix, pw);
}
}
mUi.dump(pw);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 21e2722..b2a0ce5 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -32,6 +32,7 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -43,14 +44,17 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.service.autofill.AutofillService;
import android.service.autofill.AutofillServiceInfo;
+import android.service.autofill.FieldClassification.Match;
import android.service.autofill.FillEventHistory;
import android.service.autofill.FillEventHistory.Event;
import android.service.autofill.FillResponse;
import android.service.autofill.IAutoFillService;
+import android.service.autofill.UserData;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -73,6 +77,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Random;
/**
@@ -121,6 +126,11 @@
private boolean mDisabled;
/**
+ * Data used for field classification.
+ */
+ private UserData mUserData;
+
+ /**
* Caches whether the setup completed for the current user.
*/
@GuardedBy("mLock")
@@ -183,6 +193,14 @@
}
}
+ private int getServiceUidLocked() {
+ if (mInfo == null) {
+ Slog.w(TAG, "getServiceUidLocked(): no mInfo");
+ return -1;
+ }
+ return mInfo.getServiceInfo().applicationInfo.uid;
+ }
+
@Nullable
String getServicePackageName() {
final ComponentName serviceComponent = getServiceComponentName();
@@ -449,6 +467,8 @@
sessionId = sRandom.nextInt();
} while (sessionId == NO_SESSION || mSessions.indexOfKey(sessionId) >= 0);
+ assertCallerLocked(componentName);
+
final Session newSession = new Session(this, mUi, mContext, mHandlerCaller, mUserId, mLock,
sessionId, uid, activityToken, appCallbackToken, hasCallback,
mUiLatencyHistory, mInfo.getServiceInfo().getComponentName(), componentName);
@@ -458,6 +478,34 @@
}
/**
+ * Asserts the component is owned by the caller.
+ */
+ private void assertCallerLocked(@NonNull ComponentName componentName) {
+ final PackageManager pm = mContext.getPackageManager();
+ final int callingUid = Binder.getCallingUid();
+ final int packageUid;
+ try {
+ packageUid = pm.getPackageUidAsUser(componentName.getPackageName(),
+ UserHandle.getCallingUserId());
+ } catch (NameNotFoundException e) {
+ throw new SecurityException("Could not verify UID for " + componentName);
+ }
+ if (callingUid != packageUid) {
+ final String[] packages = pm.getPackagesForUid(callingUid);
+ final String callingPackage = packages != null ? packages[0] : "uid-" + callingUid;
+ Slog.w(TAG, "App (package=" + callingPackage + ", UID=" + callingUid
+ + ") passed component (" + componentName + ") owned by UID " + packageUid);
+ mMetricsLogger.write(
+ Helper.newLogMaker(MetricsEvent.AUTOFILL_FORGED_COMPONENT_ATTEMPT,
+ callingPackage, getServicePackageName())
+ .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FORGED_COMPONENT_NAME,
+ componentName == null ? "null" : componentName.flattenToShortString()));
+
+ throw new SecurityException("Invalid component: " + componentName);
+ }
+ }
+
+ /**
* Restores a session after an activity was temporarily destroyed.
*
* @param sessionId The id of the session to restore
@@ -574,9 +622,9 @@
* Initializes the last fill selection after an autofill service returned a new
* {@link FillResponse}.
*/
- void setLastResponse(int serviceUid, int sessionId, @NonNull FillResponse response) {
+ void setLastResponse(int sessionId, @NonNull FillResponse response) {
synchronized (mLock) {
- mEventHistory = new FillEventHistory(serviceUid, sessionId, response.getClientState());
+ mEventHistory = new FillEventHistory(sessionId, response.getClientState());
}
}
@@ -612,7 +660,7 @@
if (isValidEventLocked("setAuthenticationSelected()", sessionId)) {
mEventHistory.addEvent(
new Event(Event.TYPE_AUTHENTICATION_SELECTED, null, clientState, null, null,
- null, null, null, null, null, -1));
+ null, null, null, null, null, null));
}
}
}
@@ -626,7 +674,7 @@
if (isValidEventLocked("logDatasetAuthenticationSelected()", sessionId)) {
mEventHistory.addEvent(
new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset,
- clientState, null, null, null, null, null, null, null, -1));
+ clientState, null, null, null, null, null, null, null, null));
}
}
}
@@ -638,7 +686,7 @@
synchronized (mLock) {
if (isValidEventLocked("logSaveShown()", sessionId)) {
mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null, clientState, null,
- null, null, null, null, null, null, -1));
+ null, null, null, null, null, null, null));
}
}
}
@@ -652,7 +700,7 @@
if (isValidEventLocked("logDatasetSelected()", sessionId)) {
mEventHistory.addEvent(
new Event(Event.TYPE_DATASET_SELECTED, selectedDataset, clientState, null,
- null, null, null, null, null, null, -1));
+ null, null, null, null, null, null, null));
}
}
}
@@ -667,14 +715,24 @@
@Nullable ArrayList<String> changedDatasetIds,
@Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
@Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
- @Nullable String detectedRemoteId, int detectedFieldScore) {
+ @Nullable ArrayList<AutofillId> detectedFieldIdsList,
+ @Nullable ArrayList<Match> detectedMatchesList) {
+
synchronized (mLock) {
if (isValidEventLocked("logDatasetNotSelected()", sessionId)) {
+ AutofillId[] detectedFieldsIds = null;
+ Match[] detectedMatches = null;
+ if (detectedFieldIdsList != null) {
+ detectedFieldsIds = new AutofillId[detectedFieldIdsList.size()];
+ detectedFieldIdsList.toArray(detectedFieldsIds);
+ detectedMatches = new Match[detectedMatchesList.size()];
+ detectedMatchesList.toArray(detectedMatches);
+ }
mEventHistory.addEvent(new Event(Event.TYPE_CONTEXT_COMMITTED, null,
clientState, selectedDatasets, ignoredDatasets,
changedFieldIds, changedDatasetIds,
manuallyFilledFieldIds, manuallyFilledDatasetIds,
- detectedRemoteId, detectedFieldScore));
+ detectedFieldsIds, detectedMatches));
}
}
}
@@ -688,18 +746,54 @@
*/
FillEventHistory getFillEventHistory(int callingUid) {
synchronized (mLock) {
- if (mEventHistory != null && mEventHistory.getServiceUid() == callingUid) {
+ if (mEventHistory != null
+ && isCalledByServiceLocked("getFillEventHistory", callingUid)) {
return mEventHistory;
}
}
-
return null;
}
+ // Called by Session - does not need to check uid
+ UserData getUserData() {
+ synchronized (mLock) {
+ return mUserData;
+ }
+ }
+
+ // Called by AutofillManager
+ UserData getUserData(int callingUid) {
+ synchronized (mLock) {
+ if (isCalledByServiceLocked("getUserData", callingUid)) {
+ return mUserData;
+ }
+ }
+ return null;
+ }
+
+ // Called by AutofillManager
+ void setUserData(int callingUid, UserData userData) {
+ synchronized (mLock) {
+ if (isCalledByServiceLocked("setUserData", callingUid)) {
+ mUserData = userData;
+ }
+ }
+ }
+
+ private boolean isCalledByServiceLocked(String methodName, int callingUid) {
+ if (getServiceUidLocked() != callingUid) {
+ Slog.w(TAG, methodName + "() called by UID " + callingUid
+ + ", but service UID is " + getServiceUidLocked());
+ return false;
+ }
+ return true;
+ }
+
void dumpLocked(String prefix, PrintWriter pw) {
final String prefix2 = prefix + " ";
pw.print(prefix); pw.print("User: "); pw.println(mUserId);
+ pw.print(prefix); pw.print("UID: "); pw.println(getServiceUidLocked());
pw.print(prefix); pw.print("Component: "); pw.println(mInfo != null
? mInfo.getServiceInfo().getComponentName() : null);
pw.print(prefix); pw.print("Component from settings: ");
@@ -707,7 +801,8 @@
pw.print(prefix); pw.print("Default component: ");
pw.println(mContext.getString(R.string.config_defaultAutofillService));
pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
- pw.print(prefix); pw.print("Field detection: "); pw.println(isFieldDetectionEnabled());
+ pw.print(prefix); pw.print("Field classification enabled: ");
+ pw.println(isFieldClassificationEnabled());
pw.print(prefix); pw.print("Setup complete: "); pw.println(mSetupComplete);
pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);
@@ -762,8 +857,13 @@
}
}
- pw.print(prefix); pw.println("Clients");
- mClients.dump(pw, prefix2);
+ pw.print(prefix); pw.print("Clients: ");
+ if (mClients == null) {
+ pw.println("N/A");
+ } else {
+ pw.println();
+ mClients.dump(pw, prefix2);
+ }
if (mEventHistory == null || mEventHistory.getEvents() == null
|| mEventHistory.getEvents().size() == 0) {
@@ -779,6 +879,14 @@
+ event.getDatasetId());
}
}
+
+ pw.print(prefix); pw.print("User data: ");
+ if (mUserData == null) {
+ pw.println("N/A");
+ } else {
+ pw.println();
+ mUserData.dump(prefix2, pw);
+ }
}
void destroySessionsLocked() {
@@ -951,10 +1059,10 @@
return false;
}
- // TODO(b/67867469): remove once feature is finished
- boolean isFieldDetectionEnabled() {
+ boolean isFieldClassificationEnabled() {
return Settings.Secure.getIntForUser(
- mContext.getContentResolver(), Settings.Secure.AUTOFILL_FEATURE_FIELD_DETECTION, 0,
+ mContext.getContentResolver(),
+ Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, 0,
mUserId) == 1;
}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 831c488..aea9ad0 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -97,7 +97,7 @@
private PendingRequest mPendingRequest;
public interface FillServiceCallbacks {
- void onFillRequestSuccess(int requestFlags, @Nullable FillResponse response, int serviceUid,
+ void onFillRequestSuccess(int requestFlags, @Nullable FillResponse response,
@NonNull String servicePackageName);
void onFillRequestFailure(@Nullable CharSequence message,
@NonNull String servicePackageName);
@@ -281,11 +281,11 @@
mContext.unbindService(mServiceConnection);
}
- private void dispatchOnFillRequestSuccess(PendingRequest pendingRequest,
- int callingUid, int requestFlags, FillResponse response) {
+ private void dispatchOnFillRequestSuccess(PendingRequest pendingRequest, int requestFlags,
+ FillResponse response) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
- mCallbacks.onFillRequestSuccess(requestFlags, response, callingUid,
+ mCallbacks.onFillRequestSuccess(requestFlags, response,
mComponentName.getPackageName());
}
});
@@ -546,7 +546,7 @@
final RemoteFillService remoteService = getService();
if (remoteService != null) {
remoteService.dispatchOnFillRequestSuccess(PendingFillRequest.this,
- getCallingUid(), request.getFlags(), response);
+ request.getFlags(), response);
}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 99b92b9..4e64afb 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -55,7 +55,7 @@
import android.os.SystemClock;
import android.service.autofill.AutofillService;
import android.service.autofill.Dataset;
-import android.service.autofill.FieldsDetection;
+import android.service.autofill.FieldClassification.Match;
import android.service.autofill.FillContext;
import android.service.autofill.FillRequest;
import android.service.autofill.FillResponse;
@@ -63,7 +63,9 @@
import android.service.autofill.InternalValidator;
import android.service.autofill.SaveInfo;
import android.service.autofill.SaveRequest;
+import android.service.autofill.UserData;
import android.service.autofill.ValueFinder;
+import android.service.autofill.EditDistanceScorer;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LocalLog;
@@ -236,6 +238,16 @@
structure.ensureData();
// Sanitize structure before it's sent to service.
+ final ComponentName componentNameFromApp = structure.getActivityComponent();
+ if (!mComponentName.equals(componentNameFromApp)) {
+ Slog.w(TAG, "Activity " + mComponentName + " forged different component on "
+ + "AssistStructure: " + componentNameFromApp);
+ structure.setActivityComponent(mComponentName);
+ mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_FORGED_COMPONENT_ATTEMPT)
+ .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FORGED_COMPONENT_NAME,
+ componentNameFromApp == null ? "null"
+ : componentNameFromApp.flattenToShortString()));
+ }
structure.sanitizeForParceling(true);
// Flags used to start the session.
@@ -480,7 +492,7 @@
// FillServiceCallbacks
@Override
public void onFillRequestSuccess(int requestFlags, @Nullable FillResponse response,
- int serviceUid, @NonNull String servicePackageName) {
+ @NonNull String servicePackageName) {
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#onFillRequestSuccess() rejected - session: "
@@ -494,13 +506,13 @@
}
// TODO(b/67867469): remove once feature is finished
- if (response.getFieldsDetection() != null && !mService.isFieldDetectionEnabled()) {
+ if (response.getFieldClassificationIds() != null && !mService.isFieldClassificationEnabled()) {
Slog.w(TAG, "Ignoring " + response + " because field detection is disabled");
processNullResponseLocked(requestFlags);
return;
}
- mService.setLastResponse(serviceUid, id, response);
+ mService.setLastResponse(id, response);
int sessionFinishedState = 0;
final long disableDuration = response.getDisableDuration();
@@ -903,7 +915,7 @@
final FillResponse response = mResponses.valueAt(i);
final List<Dataset> datasets = response.getDatasets();
if (datasets == null || datasets.isEmpty()) {
- if (sVerbose) Slog.v(TAG, "logContextCommitted() no datasets at " + i);
+ if (sVerbose) Slog.v(TAG, "logContextCommitted() no datasets at " + i);
} else {
for (int j = 0; j < datasets.size(); j++) {
final Dataset dataset = datasets.get(j);
@@ -926,28 +938,29 @@
}
}
}
- final FieldsDetection fieldsDetection = lastResponse.getFieldsDetection();
+ final AutofillId[] fieldClassificationIds = lastResponse.getFieldClassificationIds();
- if (!hasAtLeastOneDataset && fieldsDetection == null) {
+ if (!hasAtLeastOneDataset && fieldClassificationIds == null) {
if (sVerbose) {
Slog.v(TAG, "logContextCommittedLocked(): skipped (no datasets nor fields "
- + "detection)");
+ + "classification ids)");
}
return;
}
- final AutofillId detectableFieldId;
- final String detectableRemoteId;
- String detectedRemoteId = null;
- if (fieldsDetection == null) {
- detectableFieldId = null;
- detectableRemoteId = null;
- } else {
- detectableFieldId = fieldsDetection.getFieldId();
- detectableRemoteId = fieldsDetection.getRemoteId();
- }
+ final UserData userData = mService.getUserData();
- int detectedFieldScore = -1;
+ final ArrayList<AutofillId> detectedFieldIds;
+ final ArrayList<Match> detectedMatches;
+
+ if (userData != null) {
+ final int maxFieldsSize = UserData.getMaxFieldClassificationIdsSize();
+ detectedFieldIds = new ArrayList<>(maxFieldsSize);
+ detectedMatches = new ArrayList<>(maxFieldsSize);
+ } else {
+ detectedFieldIds = null;
+ detectedMatches = null;
+ }
for (int i = 0; i < mViewStates.size(); i++) {
final ViewState viewState = mViewStates.valueAt(i);
@@ -991,8 +1004,8 @@
final AutofillValue currentValue = viewState.getCurrentValue();
if (currentValue == null) {
if (sDebug) {
- Slog.d(TAG, "logContextCommitted(): skipping view witout current value "
- + "( " + viewState + ")");
+ Slog.d(TAG, "logContextCommitted(): skipping view without current "
+ + "value ( " + viewState + ")");
}
continue;
}
@@ -1053,18 +1066,10 @@
} // for j
}
- // Check if detectable field changed.
- if (detectableFieldId != null && detectableFieldId.equals(viewState.id)
- && currentValue.isText() && currentValue.getTextValue() != null) {
- final String actualValue = currentValue.getTextValue().toString();
- final String expectedValue = fieldsDetection.getValue();
- if (actualValue.equalsIgnoreCase(expectedValue)) {
- detectedRemoteId = detectableRemoteId;
- detectedFieldScore = 0;
- } else if (sVerbose) {
- Slog.v(TAG, "Detection mismatch for field " + detectableFieldId);
- }
- // TODO(b/67867469): set score on partial hits
+ // Sets field classification score for field
+ if (userData!= null) {
+ setScore(detectedFieldIds, detectedMatches, userData, viewState.id,
+ currentValue);
}
} // else
} // else
@@ -1077,8 +1082,8 @@
+ ", changedAutofillIds=" + changedFieldIds
+ ", changedDatasetIds=" + changedDatasetIds
+ ", manuallyFilledIds=" + manuallyFilledIds
- + ", detectableFieldId=" + detectableFieldId
- + ", detectedFieldScore=" + detectedFieldScore
+ + ", detectedFieldIds=" + detectedFieldIds
+ + ", detectedMatches=" + detectedMatches
);
}
@@ -1101,7 +1106,46 @@
mService.logContextCommitted(id, mClientState, mSelectedDatasetIds, ignoredDatasets,
changedFieldIds, changedDatasetIds,
manuallyFilledFieldIds, manuallyFilledDatasetIds,
- detectedRemoteId, detectedFieldScore);
+ detectedFieldIds, detectedMatches);
+ }
+
+ /**
+ * Adds the top score match to {@code detectedFieldsIds} and {@code detectedMatches} for
+ * {@code fieldId} based on its {@code currentValue} and {@code userData}.
+ */
+ private static void setScore(@NonNull ArrayList<AutofillId> detectedFieldIds,
+ @NonNull ArrayList<Match> detectedMatches, @NonNull UserData userData,
+ @NonNull AutofillId fieldId, @NonNull AutofillValue currentValue) {
+
+ final String[] userValues = userData.getValues();
+ final String[] remoteIds = userData.getRemoteIds();
+
+ // Sanity check
+ if (userValues == null || remoteIds == null || userValues.length != remoteIds.length) {
+ final int valuesLength = userValues == null ? -1 : userValues.length;
+ final int idsLength = remoteIds == null ? -1 : remoteIds.length;
+ Slog.w(TAG, "setScores(): user data mismatch: values.length = "
+ + valuesLength + ", ids.length = " + idsLength);
+ return;
+ }
+ String remoteId = null;
+ float topScore = 0;
+ for (int i = 0; i < userValues.length; i++) {
+ final String value = userValues[i];
+ final float score = userData.getScorer().getScore(currentValue, value);
+ if (score > topScore) {
+ topScore = score;
+ remoteId = remoteIds[i];
+ }
+ }
+
+ if (remoteId != null && topScore > 0) {
+ if (sVerbose) Slog.v(TAG, "setScores(): top score for #" + fieldId + " is " + topScore);
+ detectedFieldIds.add(fieldId);
+ detectedMatches.add(new Match(remoteId, topScore));
+ } else if (sVerbose) {
+ Slog.v(TAG, "setScores(): no top score for #" + fieldId + ": " + topScore);
+ }
}
/**
@@ -1667,7 +1711,7 @@
break;
case ACTION_VIEW_ENTERED:
if (sVerbose && virtualBounds != null) {
- Slog.w(TAG, "entered on virtual child " + id + ": " + virtualBounds);
+ Slog.v(TAG, "entered on virtual child " + id + ": " + virtualBounds);
}
requestNewFillResponseIfNecessaryLocked(id, viewState, flags);
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index dac4586..5ee3cbf 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -108,9 +108,11 @@
mCallback = callback;
final LayoutInflater inflater = LayoutInflater.from(context);
+
final ViewGroup decor = (ViewGroup) inflater.inflate(
R.layout.autofill_dataset_picker, null);
+
final RemoteViews.OnClickHandler interceptionHandler = new RemoteViews.OnClickHandler() {
@Override
public boolean onClickHandler(View view, PendingIntent pendingIntent,
@@ -153,7 +155,38 @@
mCallback.requestShowFillUi(mContentWidth, mContentHeight, mWindowPresenter);
} else {
final int datasetCount = response.getDatasets().size();
- final ArrayList<ViewItem> items = new ArrayList<>(datasetCount);
+
+ // Total items include the (optional) header and footer - we cannot use listview's
+ // addHeader() and addFooter() because it would complicate the scrolling logic.
+ int totalItems = datasetCount;
+
+ RemoteViews.OnClickHandler clickBlocker = null;
+ final RemoteViews headerPresentation = response.getHeader();
+ View header = null;
+ if (headerPresentation != null) {
+ clickBlocker = newClickBlocker();
+ header = headerPresentation.apply(context, null, clickBlocker);
+ totalItems++;
+ }
+
+ final RemoteViews footerPresentation = response.getFooter();
+ View footer = null;
+ if (footerPresentation != null) {
+ if (clickBlocker == null) { // already set for header
+ clickBlocker = newClickBlocker();
+ }
+ footer = footerPresentation.apply(context, null, clickBlocker);
+ totalItems++;
+ }
+ if (sVerbose) {
+ Slog.v(TAG, "Number datasets: " + datasetCount + " Total items: " + totalItems);
+ }
+
+ final ArrayList<ViewItem> items = new ArrayList<>(totalItems);
+ if (header != null) {
+ if (sVerbose) Slog.v(TAG, "adding header");
+ items.add(new ViewItem(null, null, null, header));
+ }
for (int i = 0; i < datasetCount; i++) {
final Dataset dataset = response.getDatasets().get(i);
final int index = dataset.getFieldIds().indexOf(focusedViewId);
@@ -176,9 +209,7 @@
String valueText = null;
if (filter == null) {
final AutofillValue value = dataset.getFieldValues().get(index);
- // If the dataset needs auth - don't add its text to allow guessing
- // its content based on how filtering behaves.
- if (value != null && value.isText() && dataset.getAuthentication() == null) {
+ if (value != null && value.isText()) {
valueText = value.getTextValue().toString().toLowerCase();
}
}
@@ -186,6 +217,10 @@
items.add(new ViewItem(dataset, filter, valueText, view));
}
}
+ if (footer != null) {
+ if (sVerbose) Slog.v(TAG, "adding footer");
+ items.add(new ViewItem(null, null, null, footer));
+ }
mAdapter = new ItemsAdapter(items);
@@ -194,7 +229,12 @@
mListView.setVisibility(View.VISIBLE);
mListView.setOnItemClickListener((adapter, view, position, id) -> {
final ViewItem vi = mAdapter.getItem(position);
- mCallback.onDatasetPicked(vi.getDataset());
+ if (vi.dataset == null) {
+ // Clicked on header or footer; ignore.
+ if (sDebug) Slog.d(TAG, "Ignoring click on item " + position + ": " + view);
+ return;
+ }
+ mCallback.onDatasetPicked(vi.dataset);
});
if (filterText == null) {
@@ -208,6 +248,20 @@
}
}
+ /**
+ * Creates a remoteview interceptor used to block clicks.
+ */
+ private RemoteViews.OnClickHandler newClickBlocker() {
+ return new RemoteViews.OnClickHandler() {
+ @Override
+ public boolean onClickHandler(View view, PendingIntent pendingIntent,
+ Intent fillInIntent) {
+ if (sVerbose) Slog.v(TAG, "Ignoring click on " + view);
+ return true;
+ }
+ };
+ }
+
private void applyNewFilterText() {
final int oldCount = mAdapter.getCount();
mAdapter.getFilter().filter(mFilterText, (count) -> {
@@ -300,7 +354,7 @@
MeasureSpec.AT_MOST);
final int itemCount = mAdapter.getCount();
for (int i = 0; i < itemCount; i++) {
- View view = mAdapter.getItem(i).getView();
+ View view = mAdapter.getItem(i).view;
view.measure(widthMeasureSpec, heightMeasureSpec);
final int clampedMeasuredWidth = Math.min(view.getMeasuredWidth(), maxSize.x);
final int newContentWidth = Math.max(mContentWidth, clampedMeasuredWidth);
@@ -338,33 +392,21 @@
outPoint.y = (int) typedValue.getFraction(outPoint.y, outPoint.y);
}
+ /**
+ * An item for the list view - either a (clickable) dataset or a (read-only) header / footer.
+ */
private static class ViewItem {
- private final String mValue;
- private final Dataset mDataset;
- private final View mView;
- private final Pattern mFilter;
+ public final @Nullable String value;
+ public final @Nullable Dataset dataset;
+ public final @NonNull View view;
+ public final @Nullable Pattern filter;
- ViewItem(Dataset dataset, Pattern filter, String value, View view) {
- mDataset = dataset;
- mValue = value;
- mView = view;
- mFilter = filter;
- }
-
- public Pattern getFilter() {
- return mFilter;
- }
-
- public View getView() {
- return mView;
- }
-
- public Dataset getDataset() {
- return mDataset;
- }
-
- public String getValue() {
- return mValue;
+ ViewItem(@Nullable Dataset dataset, @Nullable Pattern filter, @Nullable String value,
+ @NonNull View view) {
+ this.dataset = dataset;
+ this.value = value;
+ this.view = view;
+ this.filter = filter;
}
}
@@ -527,15 +569,13 @@
final int itemCount = mAllItems.size();
for (int i = 0; i < itemCount; i++) {
final ViewItem item = mAllItems.get(i);
- final String value = item.getValue();
- final Pattern filter = item.getFilter();
final boolean matches;
- if (filter != null) {
- matches = filter.matcher(constraintLowerCase).matches();
+ if (item.filter != null) {
+ matches = item.filter.matcher(constraintLowerCase).matches();
} else {
- matches = (value == null)
- ? (item.mDataset.getAuthentication() == null)
- : value.toLowerCase().startsWith(constraintLowerCase);
+ matches = (item.value == null)
+ ? (item.dataset.getAuthentication() == null)
+ : item.value.toLowerCase().startsWith(constraintLowerCase);
}
if (matches) {
filteredItems.add(item);
@@ -582,7 +622,7 @@
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- return getItem(position).getView();
+ return getItem(position).view;
}
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
deleted file mode 100644
index e92a564..0000000
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ /dev/null
@@ -1,11482 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME;
-import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION;
-import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_OLD_VERSION;
-import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_POLICY_ALLOW_APKS;
-import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_MANIFEST_PACKAGE_NAME;
-import static android.app.backup.BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT;
-import static android.app.backup.BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY;
-import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER;
-import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH;
-import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_SYSTEM_APP_NO_AGENT;
-import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE;
-import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_APK_NOT_INSTALLED;
-import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK;
-import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_MISSING_SIGNATURE;
-import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE;
-import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_RESTORE_ANY_VERSION;
-import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSIONS_MATCH;
-import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;
-
-import android.app.ActivityManager;
-import android.app.AlarmManager;
-import android.app.AppGlobals;
-import android.app.ApplicationThreadConstants;
-import android.app.IActivityManager;
-import android.app.IBackupAgent;
-import android.app.PackageInstallObserver;
-import android.app.PendingIntent;
-import android.app.backup.BackupAgent;
-import android.app.backup.BackupDataInput;
-import android.app.backup.BackupDataOutput;
-import android.app.backup.BackupManager;
-import android.app.backup.BackupManagerMonitor;
-import android.app.backup.BackupProgress;
-import android.app.backup.BackupTransport;
-import android.app.backup.FullBackup;
-import android.app.backup.FullBackupDataOutput;
-import android.app.backup.IBackupManager;
-import android.app.backup.IBackupManagerMonitor;
-import android.app.backup.IBackupObserver;
-import android.app.backup.IFullBackupRestoreObserver;
-import android.app.backup.IRestoreObserver;
-import android.app.backup.IRestoreSession;
-import android.app.backup.ISelectBackupTransportCallback;
-import android.app.backup.RestoreDescription;
-import android.app.backup.RestoreSet;
-import android.app.backup.SelectBackupTransportCallback;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageDataObserver;
-import android.content.pm.IPackageDeleteObserver;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.Signature;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.PowerManager.ServiceType;
-import android.os.PowerSaveState;
-import android.os.Binder;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.Environment.UserEnvironment;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.ParcelFileDescriptor;
-import android.os.PowerManager;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SELinux;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.Trace;
-import android.os.UserHandle;
-import android.os.WorkSource;
-import android.os.storage.IStorageManager;
-import android.os.storage.StorageManager;
-import android.provider.Settings;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.text.TextUtils;
-import android.util.ArraySet;
-import android.util.AtomicFile;
-import android.util.EventLog;
-import android.util.Log;
-import android.util.Pair;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.StringBuilderPrinter;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.backup.IBackupTransport;
-import com.android.internal.backup.IObbBackupService;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.DumpUtils;
-import com.android.server.AppWidgetBackupBridge;
-import com.android.server.EventLogTags;
-import com.android.server.SystemConfig;
-import com.android.server.SystemService;
-import com.android.server.backup.PackageManagerBackupAgent.Metadata;
-
-import libcore.io.IoUtils;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.EOFException;
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.io.RandomAccessFile;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.text.SimpleDateFormat;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Queue;
-import java.util.Random;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.zip.Deflater;
-import java.util.zip.DeflaterOutputStream;
-import java.util.zip.InflaterInputStream;
-
-import javax.crypto.BadPaddingException;
-import javax.crypto.Cipher;
-import javax.crypto.CipherInputStream;
-import javax.crypto.CipherOutputStream;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.PBEKeySpec;
-import javax.crypto.spec.SecretKeySpec;
-
-/**
- * @Deprecated Use RefactoredBackupManagerService instead. This class is only
- * kept for fallback and archeology reasons and will be removed soon.
- */
-public class BackupManagerService implements BackupManagerServiceInterface {
-
- private static final String TAG = "BackupManagerService";
- static final boolean DEBUG = true;
- static final boolean MORE_DEBUG = false;
- static final boolean DEBUG_SCHEDULING = MORE_DEBUG || true;
-
- // File containing backup-enabled state. Contains a single byte;
- // nonzero == enabled. File missing or contains a zero byte == disabled.
- static final String BACKUP_ENABLE_FILE = "backup_enabled";
-
- // System-private key used for backing up an app's widget state. Must
- // begin with U+FFxx by convention (we reserve all keys starting
- // with U+FF00 or higher for system use).
- static final String KEY_WIDGET_STATE = "\uffed\uffedwidget";
-
- // Historical and current algorithm names
- static final String PBKDF_CURRENT = "PBKDF2WithHmacSHA1";
- static final String PBKDF_FALLBACK = "PBKDF2WithHmacSHA1And8bit";
-
- // Name and current contents version of the full-backup manifest file
- //
- // Manifest version history:
- //
- // 1 : initial release
- static final String BACKUP_MANIFEST_FILENAME = "_manifest";
- static final int BACKUP_MANIFEST_VERSION = 1;
-
- // External archive format version history:
- //
- // 1 : initial release
- // 2 : no format change per se; version bump to facilitate PBKDF2 version skew detection
- // 3 : introduced "_meta" metadata file; no other format change per se
- // 4 : added support for new device-encrypted storage locations
- // 5 : added support for key-value packages
- static final int BACKUP_FILE_VERSION = 5;
- static final String BACKUP_FILE_HEADER_MAGIC = "ANDROID BACKUP\n";
- static final int BACKUP_PW_FILE_VERSION = 2;
- static final String BACKUP_METADATA_FILENAME = "_meta";
- static final int BACKUP_METADATA_VERSION = 1;
- static final int BACKUP_WIDGET_METADATA_TOKEN = 0x01FFED01;
-
- static final int TAR_HEADER_LONG_RADIX = 8;
- static final int TAR_HEADER_OFFSET_FILESIZE = 124;
- static final int TAR_HEADER_LENGTH_FILESIZE = 12;
- static final int TAR_HEADER_OFFSET_MODTIME = 136;
- static final int TAR_HEADER_LENGTH_MODTIME = 12;
- static final int TAR_HEADER_OFFSET_MODE = 100;
- static final int TAR_HEADER_LENGTH_MODE = 8;
- static final int TAR_HEADER_OFFSET_PATH_PREFIX = 345;
- static final int TAR_HEADER_LENGTH_PATH_PREFIX = 155;
- static final int TAR_HEADER_OFFSET_PATH = 0;
- static final int TAR_HEADER_LENGTH_PATH = 100;
- static final int TAR_HEADER_OFFSET_TYPE_CHAR = 156;
-
- static final boolean COMPRESS_FULL_BACKUPS = true; // should be true in production
-
- static final String SETTINGS_PACKAGE = "com.android.providers.settings";
- static final String SHARED_BACKUP_AGENT_PACKAGE = "com.android.sharedstoragebackup";
- static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
-
- // Retry interval for clear/init when the transport is unavailable
- private static final long TRANSPORT_RETRY_INTERVAL = 1 * AlarmManager.INTERVAL_HOUR;
-
- private static final String RUN_BACKUP_ACTION = "android.app.backup.intent.RUN";
- private static final String RUN_INITIALIZE_ACTION = "android.app.backup.intent.INIT";
- private static final int MSG_RUN_BACKUP = 1;
- private static final int MSG_RUN_ADB_BACKUP = 2;
- private static final int MSG_RUN_RESTORE = 3;
- private static final int MSG_RUN_CLEAR = 4;
- private static final int MSG_RUN_GET_RESTORE_SETS = 6;
- private static final int MSG_RESTORE_SESSION_TIMEOUT = 8;
- private static final int MSG_FULL_CONFIRMATION_TIMEOUT = 9;
- private static final int MSG_RUN_ADB_RESTORE = 10;
- private static final int MSG_RETRY_INIT = 11;
- private static final int MSG_RETRY_CLEAR = 12;
- private static final int MSG_WIDGET_BROADCAST = 13;
- private static final int MSG_RUN_FULL_TRANSPORT_BACKUP = 14;
- private static final int MSG_REQUEST_BACKUP = 15;
- private static final int MSG_SCHEDULE_BACKUP_PACKAGE = 16;
- private static final int MSG_BACKUP_OPERATION_TIMEOUT = 17;
- private static final int MSG_RESTORE_OPERATION_TIMEOUT = 18;
-
- // backup task state machine tick
- static final int MSG_BACKUP_RESTORE_STEP = 20;
- static final int MSG_OP_COMPLETE = 21;
-
- // Timeout interval for deciding that a bind or clear-data has taken too long
- static final long TIMEOUT_INTERVAL = 10 * 1000;
-
- // Timeout intervals for agent backup & restore operations
- static final long TIMEOUT_BACKUP_INTERVAL = 30 * 1000;
- static final long TIMEOUT_FULL_BACKUP_INTERVAL = 5 * 60 * 1000;
- static final long TIMEOUT_SHARED_BACKUP_INTERVAL = 30 * 60 * 1000;
- static final long TIMEOUT_RESTORE_INTERVAL = 60 * 1000;
- static final long TIMEOUT_RESTORE_FINISHED_INTERVAL = 30 * 1000;
-
- // User confirmation timeout for a full backup/restore operation. It's this long in
- // order to give them time to enter the backup password.
- static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000;
-
- // If an app is busy when we want to do a full-data backup, how long to defer the retry.
- // This is fuzzed, so there are two parameters; backoff_min + Rand[0, backoff_fuzz)
- static final long BUSY_BACKOFF_MIN_MILLIS = 1000 * 60 * 60; // one hour
- static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2; // two hours
-
- BackupManagerConstants mConstants;
- Context mContext;
- private PackageManager mPackageManager;
- IPackageManager mPackageManagerBinder;
- private IActivityManager mActivityManager;
- private PowerManager mPowerManager;
- private AlarmManager mAlarmManager;
- private IStorageManager mStorageManager;
-
- IBackupManager mBackupManagerBinder;
-
- private final TransportManager mTransportManager;
-
- boolean mEnabled; // access to this is synchronized on 'this'
- boolean mProvisioned;
- boolean mAutoRestore;
- PowerManager.WakeLock mWakelock;
- BackupHandler mBackupHandler;
- PendingIntent mRunBackupIntent, mRunInitIntent;
- BroadcastReceiver mRunBackupReceiver, mRunInitReceiver;
- // map UIDs to the set of participating packages under that UID
- final SparseArray<HashSet<String>> mBackupParticipants
- = new SparseArray<HashSet<String>>();
- // set of backup services that have pending changes
- class BackupRequest {
- public String packageName;
-
- BackupRequest(String pkgName) {
- packageName = pkgName;
- }
-
- public String toString() {
- return "BackupRequest{pkg=" + packageName + "}";
- }
- }
- // Backups that we haven't started yet. Keys are package names.
- HashMap<String,BackupRequest> mPendingBackups
- = new HashMap<String,BackupRequest>();
-
- // Pseudoname that we use for the Package Manager metadata "package"
- static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
-
- // locking around the pending-backup management
- final Object mQueueLock = new Object();
-
- // The thread performing the sequence of queued backups binds to each app's agent
- // in succession. Bind notifications are asynchronously delivered through the
- // Activity Manager; use this lock object to signal when a requested binding has
- // completed.
- final Object mAgentConnectLock = new Object();
- IBackupAgent mConnectedAgent;
- volatile boolean mBackupRunning;
- volatile boolean mConnecting;
- volatile long mLastBackupPass;
-
- // For debugging, we maintain a progress trace of operations during backup
- static final boolean DEBUG_BACKUP_TRACE = true;
- final List<String> mBackupTrace = new ArrayList<String>();
-
- // A similar synchronization mechanism around clearing apps' data for restore
- final Object mClearDataLock = new Object();
- volatile boolean mClearingData;
-
- @GuardedBy("mPendingRestores")
- private boolean mIsRestoreInProgress;
- @GuardedBy("mPendingRestores")
- private final Queue<PerformUnifiedRestoreTask> mPendingRestores = new ArrayDeque<>();
-
- ActiveRestoreSession mActiveRestoreSession;
-
- // Watch the device provisioning operation during setup
- ContentObserver mProvisionedObserver;
-
- // The published binder is actually to a singleton trampoline object that calls
- // through to the proper code. This indirection lets us turn down the heavy
- // implementation object on the fly without disturbing binders that have been
- // cached elsewhere in the system.
- static Trampoline sInstance;
- static Trampoline getInstance() {
- // Always constructed during system bringup, so no need to lazy-init
- return sInstance;
- }
-
- public static final class Lifecycle extends SystemService {
-
- public Lifecycle(Context context) {
- super(context);
- sInstance = new Trampoline(context);
- }
-
- @Override
- public void onStart() {
- publishBinderService(Context.BACKUP_SERVICE, sInstance);
- }
-
- @Override
- public void onUnlockUser(int userId) {
- if (userId == UserHandle.USER_SYSTEM) {
- sInstance.unlockSystemUser();
- }
- }
- }
-
- // Called through the trampoline from onUnlockUser(), then we buck the work
- // off to the background thread to keep the unlock time down.
- public void unlockSystemUser() {
- // Migrate legacy setting
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup migrate");
- if (!backupSettingMigrated(UserHandle.USER_SYSTEM)) {
- if (DEBUG) {
- Slog.i(TAG, "Backup enable apparently not migrated");
- }
- final ContentResolver r = sInstance.mContext.getContentResolver();
- final int enableState = Settings.Secure.getIntForUser(r,
- Settings.Secure.BACKUP_ENABLED, -1, UserHandle.USER_SYSTEM);
- if (enableState >= 0) {
- if (DEBUG) {
- Slog.i(TAG, "Migrating enable state " + (enableState != 0));
- }
- writeBackupEnableState(enableState != 0, UserHandle.USER_SYSTEM);
- Settings.Secure.putStringForUser(r,
- Settings.Secure.BACKUP_ENABLED, null, UserHandle.USER_SYSTEM);
- } else {
- if (DEBUG) {
- Slog.i(TAG, "Backup not yet configured; retaining null enable state");
- }
- }
- }
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable");
- try {
- sInstance.setBackupEnabled(readBackupEnableState(UserHandle.USER_SYSTEM));
- } catch (RemoteException e) {
- // can't happen; it's a local object
- }
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- }
-
- class ProvisionedObserver extends ContentObserver {
- public ProvisionedObserver(Handler handler) {
- super(handler);
- }
-
- public void onChange(boolean selfChange) {
- final boolean wasProvisioned = mProvisioned;
- final boolean isProvisioned = deviceIsProvisioned();
- // latch: never unprovision
- mProvisioned = wasProvisioned || isProvisioned;
- if (MORE_DEBUG) {
- Slog.d(TAG, "Provisioning change: was=" + wasProvisioned
- + " is=" + isProvisioned + " now=" + mProvisioned);
- }
-
- synchronized (mQueueLock) {
- if (mProvisioned && !wasProvisioned && mEnabled) {
- // we're now good to go, so start the backup alarms
- if (MORE_DEBUG) Slog.d(TAG, "Now provisioned, so starting backups");
- KeyValueBackupJob.schedule(mContext, mConstants);
- scheduleNextFullBackupJob(0);
- }
- }
- }
- }
-
- class RestoreGetSetsParams {
- public IBackupTransport transport;
- public ActiveRestoreSession session;
- public IRestoreObserver observer;
- public IBackupManagerMonitor monitor;
-
- RestoreGetSetsParams(IBackupTransport _transport, ActiveRestoreSession _session,
- IRestoreObserver _observer, IBackupManagerMonitor _monitor) {
- transport = _transport;
- session = _session;
- observer = _observer;
- monitor = _monitor;
- }
- }
-
- class RestoreParams {
- public IBackupTransport transport;
- public String dirName;
- public IRestoreObserver observer;
- public IBackupManagerMonitor monitor;
- public long token;
- public PackageInfo pkgInfo;
- public int pmToken; // in post-install restore, the PM's token for this transaction
- public boolean isSystemRestore;
- public String[] filterSet;
-
- /**
- * Restore a single package; no kill after restore
- */
- RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
- IBackupManagerMonitor _monitor, long _token, PackageInfo _pkg) {
- transport = _transport;
- dirName = _dirName;
- observer = _obs;
- monitor = _monitor;
- token = _token;
- pkgInfo = _pkg;
- pmToken = 0;
- isSystemRestore = false;
- filterSet = null;
- }
-
- /**
- * Restore at install: PM token needed, kill after restore
- */
- RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
- IBackupManagerMonitor _monitor, long _token, String _pkgName, int _pmToken) {
- transport = _transport;
- dirName = _dirName;
- observer = _obs;
- monitor = _monitor;
- token = _token;
- pkgInfo = null;
- pmToken = _pmToken;
- isSystemRestore = false;
- filterSet = new String[] { _pkgName };
- }
-
- /**
- * Restore everything possible. This is the form that Setup Wizard or similar
- * restore UXes use.
- */
- RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
- IBackupManagerMonitor _monitor, long _token) {
- transport = _transport;
- dirName = _dirName;
- observer = _obs;
- monitor = _monitor;
- token = _token;
- pkgInfo = null;
- pmToken = 0;
- isSystemRestore = true;
- filterSet = null;
- }
-
- /**
- * Restore some set of packages. Leave this one up to the caller to specify
- * whether it's to be considered a system-level restore.
- */
- RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
- IBackupManagerMonitor _monitor, long _token,
- String[] _filterSet, boolean _isSystemRestore) {
- transport = _transport;
- dirName = _dirName;
- observer = _obs;
- monitor = _monitor;
- token = _token;
- pkgInfo = null;
- pmToken = 0;
- isSystemRestore = _isSystemRestore;
- filterSet = _filterSet;
- }
- }
-
- class ClearParams {
- public IBackupTransport transport;
- public PackageInfo packageInfo;
-
- ClearParams(IBackupTransport _transport, PackageInfo _info) {
- transport = _transport;
- packageInfo = _info;
- }
- }
-
- class ClearRetryParams {
- public String transportName;
- public String packageName;
-
- ClearRetryParams(String transport, String pkg) {
- transportName = transport;
- packageName = pkg;
- }
- }
-
- // Parameters used by adbBackup() and adbRestore()
- class AdbParams {
- public ParcelFileDescriptor fd;
- public final AtomicBoolean latch;
- public IFullBackupRestoreObserver observer;
- public String curPassword; // filled in by the confirmation step
- public String encryptPassword;
-
- AdbParams() {
- latch = new AtomicBoolean(false);
- }
- }
-
- class AdbBackupParams extends AdbParams {
- public boolean includeApks;
- public boolean includeObbs;
- public boolean includeShared;
- public boolean doWidgets;
- public boolean allApps;
- public boolean includeSystem;
- public boolean doCompress;
- public boolean includeKeyValue;
- public String[] packages;
-
- AdbBackupParams(ParcelFileDescriptor output, boolean saveApks, boolean saveObbs,
- boolean saveShared, boolean alsoWidgets, boolean doAllApps, boolean doSystem,
- boolean compress, boolean doKeyValue, String[] pkgList) {
- fd = output;
- includeApks = saveApks;
- includeObbs = saveObbs;
- includeShared = saveShared;
- doWidgets = alsoWidgets;
- allApps = doAllApps;
- includeSystem = doSystem;
- doCompress = compress;
- includeKeyValue = doKeyValue;
- packages = pkgList;
- }
- }
-
- class AdbRestoreParams extends AdbParams {
- AdbRestoreParams(ParcelFileDescriptor input) {
- fd = input;
- }
- }
-
- class BackupParams {
- public IBackupTransport transport;
- public String dirName;
- public ArrayList<String> kvPackages;
- public ArrayList<String> fullPackages;
- public IBackupObserver observer;
- public IBackupManagerMonitor monitor;
- public boolean userInitiated;
- public boolean nonIncrementalBackup;
-
- BackupParams(IBackupTransport transport, String dirName, ArrayList<String> kvPackages,
- ArrayList<String> fullPackages, IBackupObserver observer,
- IBackupManagerMonitor monitor,boolean userInitiated, boolean nonIncrementalBackup) {
- this.transport = transport;
- this.dirName = dirName;
- this.kvPackages = kvPackages;
- this.fullPackages = fullPackages;
- this.observer = observer;
- this.monitor = monitor;
- this.userInitiated = userInitiated;
- this.nonIncrementalBackup = nonIncrementalBackup;
- }
- }
-
- // Bookkeeping of in-flight operations for timeout etc. purposes. The operation
- // token is the index of the entry in the pending-operations list.
- static final int OP_PENDING = 0;
- static final int OP_ACKNOWLEDGED = 1;
- static final int OP_TIMEOUT = -1;
-
- // Waiting for backup agent to respond during backup operation.
- static final int OP_TYPE_BACKUP_WAIT = 0;
-
- // Waiting for backup agent to respond during restore operation.
- static final int OP_TYPE_RESTORE_WAIT = 1;
-
- // An entire backup operation spanning multiple packages.
- private static final int OP_TYPE_BACKUP = 2;
-
- class Operation {
- int state;
- final BackupRestoreTask callback;
- final int type;
-
- Operation(int initialState, BackupRestoreTask callbackObj, int type) {
- state = initialState;
- callback = callbackObj;
- this.type = type;
- }
- }
-
- /**
- * mCurrentOperations contains the list of currently active operations.
- *
- * If type of operation is OP_TYPE_WAIT, it are waiting for an ack or timeout.
- * An operation wraps a BackupRestoreTask within it.
- * It's the responsibility of this task to remove the operation from this array.
- *
- * A BackupRestore task gets notified of ack/timeout for the operation via
- * BackupRestoreTask#handleCancel, BackupRestoreTask#operationComplete and notifyAll called
- * on the mCurrentOpLock. {@link BackupManagerService#waitUntilOperationComplete(int)} is
- * used in various places to 'wait' for notifyAll and detect change of pending state of an
- * operation. So typically, an operation will be removed from this array by:
- * - BackupRestoreTask#handleCancel and
- * - BackupRestoreTask#operationComplete OR waitUntilOperationComplete. Do not remove at both
- * these places because waitUntilOperationComplete relies on the operation being present to
- * determine its completion status.
- *
- * If type of operation is OP_BACKUP, it is a task running backups. It provides a handle to
- * cancel backup tasks.
- */
- @GuardedBy("mCurrentOpLock")
- final SparseArray<Operation> mCurrentOperations = new SparseArray<Operation>();
- final Object mCurrentOpLock = new Object();
- final Random mTokenGenerator = new Random();
- final AtomicInteger mNextToken = new AtomicInteger();
-
- final SparseArray<AdbParams> mAdbBackupRestoreConfirmations = new SparseArray<AdbParams>();
-
- // Where we keep our journal files and other bookkeeping
- File mBaseStateDir;
- File mDataDir;
- File mJournalDir;
- File mJournal;
-
- // Backup password, if any, and the file where it's saved. What is stored is not the
- // password text itself; it's the result of a PBKDF2 hash with a randomly chosen (but
- // persisted) salt. Validation is performed by running the challenge text through the
- // same PBKDF2 cycle with the persisted salt; if the resulting derived key string matches
- // the saved hash string, then the challenge text matches the originally supplied
- // password text.
- private final SecureRandom mRng = new SecureRandom();
- private String mPasswordHash;
- private File mPasswordHashFile;
- private int mPasswordVersion;
- private File mPasswordVersionFile;
- private byte[] mPasswordSalt;
-
- // Configuration of PBKDF2 that we use for generating pw hashes and intermediate keys
- static final int PBKDF2_HASH_ROUNDS = 10000;
- static final int PBKDF2_KEY_SIZE = 256; // bits
- static final int PBKDF2_SALT_SIZE = 512; // bits
- static final String ENCRYPTION_ALGORITHM_NAME = "AES-256";
-
- // Keep a log of all the apps we've ever backed up, and what the
- // dataset tokens are for both the current backup dataset and
- // the ancestral dataset.
- private File mEverStored;
- HashSet<String> mEverStoredApps = new HashSet<String>();
-
- static final int CURRENT_ANCESTRAL_RECORD_VERSION = 1; // increment when the schema changes
- File mTokenFile;
- Set<String> mAncestralPackages = null;
- long mAncestralToken = 0;
- long mCurrentToken = 0;
-
- // Persistently track the need to do a full init
- static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
- ArraySet<String> mPendingInits = new ArraySet<String>(); // transport names
-
- // Round-robin queue for scheduling full backup passes
- static final int SCHEDULE_FILE_VERSION = 1; // current version of the schedule file
- class FullBackupEntry implements Comparable<FullBackupEntry> {
- String packageName;
- long lastBackup;
-
- FullBackupEntry(String pkg, long when) {
- packageName = pkg;
- lastBackup = when;
- }
-
- @Override
- public int compareTo(FullBackupEntry other) {
- if (lastBackup < other.lastBackup) return -1;
- else if (lastBackup > other.lastBackup) return 1;
- else return 0;
- }
- }
-
- File mFullBackupScheduleFile;
- // If we're running a schedule-driven full backup, this is the task instance doing it
-
- @GuardedBy("mQueueLock")
- PerformFullTransportBackupTask mRunningFullBackupTask;
-
- @GuardedBy("mQueueLock")
- ArrayList<FullBackupEntry> mFullBackupQueue;
-
- // Utility: build a new random integer token. The low bits are the ordinal of the
- // operation for near-time uniqueness, and the upper bits are random for app-
- // side unpredictability.
- @Override
- public int generateRandomIntegerToken() {
- int token = mTokenGenerator.nextInt();
- if (token < 0) token = -token;
- token &= ~0xFF;
- token |= (mNextToken.incrementAndGet() & 0xFF);
- return token;
- }
-
- // High level policy: apps are generally ineligible for backup if certain conditions apply
- public static boolean appIsEligibleForBackup(ApplicationInfo app, PackageManager pm) {
- // 1. their manifest states android:allowBackup="false"
- if ((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
- return false;
- }
-
- // 2. they run as a system-level uid but do not supply their own backup agent
- if ((app.uid < Process.FIRST_APPLICATION_UID) && (app.backupAgentName == null)) {
- return false;
- }
-
- // 3. it is the special shared-storage backup package used for 'adb backup'
- if (app.packageName.equals(BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE)) {
- return false;
- }
-
- // 4. it is an "instant" app
- if (app.isInstantApp()) {
- return false;
- }
-
- // Everything else checks out; the only remaining roadblock would be if the
- // package were disabled
- return !appIsDisabled(app, pm);
- }
-
- // Checks if the app is in a stopped state. This is not part of the general "eligible for
- // backup?" check because we *do* still need to restore data to apps in this state (e.g.
- // newly-installing ones)
- private static boolean appIsStopped(ApplicationInfo app) {
- return ((app.flags & ApplicationInfo.FLAG_STOPPED) != 0);
- }
-
- private static boolean appIsDisabled(ApplicationInfo app, PackageManager pm) {
- switch (pm.getApplicationEnabledSetting(app.packageName)) {
- case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
- case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER:
- case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
- return true;
-
- default:
- return false;
- }
- }
-
- /* does *not* check overall backup eligibility policy! */
- private static boolean appGetsFullBackup(PackageInfo pkg) {
- if (pkg.applicationInfo.backupAgentName != null) {
- // If it has an agent, it gets full backups only if it says so
- return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0;
- }
-
- // No agent or fullBackupOnly="true" means we do indeed perform full-data backups for it
- return true;
- }
-
- /* adb backup: is this app only capable of doing key/value? We say otherwise if
- * the app has a backup agent and does not say fullBackupOnly,
- */
- private static boolean appIsKeyValueOnly(PackageInfo pkg) {
- return !appGetsFullBackup(pkg);
- }
-
- /*
- * Construct a backup agent instance for the metadata pseudopackage. This is a
- * process-local non-lifecycle agent instance, so we manually set up the context
- * topology for it.
- */
- PackageManagerBackupAgent makeMetadataAgent() {
- PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(mPackageManager);
- pmAgent.attach(mContext);
- pmAgent.onCreate();
- return pmAgent;
- }
-
- /*
- * Same as above but with the explicit package-set configuration.
- */
- PackageManagerBackupAgent makeMetadataAgent(List<PackageInfo> packages) {
- PackageManagerBackupAgent pmAgent =
- new PackageManagerBackupAgent(mPackageManager, packages);
- pmAgent.attach(mContext);
- pmAgent.onCreate();
- return pmAgent;
- }
-
- // ----- Asynchronous backup/restore handler thread -----
-
- private class BackupHandler extends Handler {
- public BackupHandler(Looper looper) {
- super(looper);
- }
-
- public void handleMessage(Message msg) {
-
- switch (msg.what) {
- case MSG_RUN_BACKUP:
- {
- mLastBackupPass = System.currentTimeMillis();
-
- IBackupTransport transport = mTransportManager.getCurrentTransportBinder();
- if (transport == null) {
- Slog.v(TAG, "Backup requested but no transport available");
- synchronized (mQueueLock) {
- mBackupRunning = false;
- }
- mWakelock.release();
- break;
- }
-
- // snapshot the pending-backup set and work on that
- ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
- File oldJournal = mJournal;
- synchronized (mQueueLock) {
- // Do we have any work to do? Construct the work queue
- // then release the synchronization lock to actually run
- // the backup.
- if (mPendingBackups.size() > 0) {
- for (BackupRequest b: mPendingBackups.values()) {
- queue.add(b);
- }
- if (DEBUG) Slog.v(TAG, "clearing pending backups");
- mPendingBackups.clear();
-
- // Start a new backup-queue journal file too
- mJournal = null;
-
- }
- }
-
- // At this point, we have started a new journal file, and the old
- // file identity is being passed to the backup processing task.
- // When it completes successfully, that old journal file will be
- // deleted. If we crash prior to that, the old journal is parsed
- // at next boot and the journaled requests fulfilled.
- boolean staged = true;
- if (queue.size() > 0) {
- // Spin up a backup state sequence and set it running
- try {
- String dirName = transport.transportDirName();
- PerformBackupTask pbt = new PerformBackupTask(transport, dirName, queue,
- oldJournal, null, null, Collections.<String>emptyList(), false,
- false /* nonIncremental */);
- Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt);
- sendMessage(pbtMessage);
- } catch (Exception e) {
- // unable to ask the transport its dir name -- transient failure, since
- // the above check succeeded. Try again next time.
- Slog.e(TAG, "Transport became unavailable attempting backup"
- + " or error initializing backup task", e);
- staged = false;
- }
- } else {
- Slog.v(TAG, "Backup requested but nothing pending");
- staged = false;
- }
-
- if (!staged) {
- // if we didn't actually hand off the wakelock, rewind until next time
- synchronized (mQueueLock) {
- mBackupRunning = false;
- }
- mWakelock.release();
- }
- break;
- }
-
- case MSG_BACKUP_RESTORE_STEP:
- {
- try {
- BackupRestoreTask task = (BackupRestoreTask) msg.obj;
- if (MORE_DEBUG) Slog.v(TAG, "Got next step for " + task + ", executing");
- task.execute();
- } catch (ClassCastException e) {
- Slog.e(TAG, "Invalid backup task in flight, obj=" + msg.obj);
- }
- break;
- }
-
- case MSG_OP_COMPLETE:
- {
- try {
- Pair<BackupRestoreTask, Long> taskWithResult =
- (Pair<BackupRestoreTask, Long>) msg.obj;
- taskWithResult.first.operationComplete(taskWithResult.second);
- } catch (ClassCastException e) {
- Slog.e(TAG, "Invalid completion in flight, obj=" + msg.obj);
- }
- break;
- }
-
- case MSG_RUN_ADB_BACKUP:
- {
- // TODO: refactor full backup to be a looper-based state machine
- // similar to normal backup/restore.
- AdbBackupParams params = (AdbBackupParams)msg.obj;
- PerformAdbBackupTask task = new PerformAdbBackupTask(params.fd,
- params.observer, params.includeApks, params.includeObbs,
- params.includeShared, params.doWidgets, params.curPassword,
- params.encryptPassword, params.allApps, params.includeSystem,
- params.doCompress, params.includeKeyValue, params.packages, params.latch);
- (new Thread(task, "adb-backup")).start();
- break;
- }
-
- case MSG_RUN_FULL_TRANSPORT_BACKUP:
- {
- PerformFullTransportBackupTask task = (PerformFullTransportBackupTask) msg.obj;
- (new Thread(task, "transport-backup")).start();
- break;
- }
-
- case MSG_RUN_RESTORE:
- {
- RestoreParams params = (RestoreParams)msg.obj;
- Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
-
- PerformUnifiedRestoreTask task = new PerformUnifiedRestoreTask(params.transport,
- params.observer, params.monitor, params.token, params.pkgInfo,
- params.pmToken, params.isSystemRestore, params.filterSet);
-
- synchronized (mPendingRestores) {
- if (mIsRestoreInProgress) {
- if (DEBUG) {
- Slog.d(TAG, "Restore in progress, queueing.");
- }
- mPendingRestores.add(task);
- // This task will be picked up and executed when the the currently running
- // restore task finishes.
- } else {
- if (DEBUG) {
- Slog.d(TAG, "Starting restore.");
- }
- mIsRestoreInProgress = true;
- Message restoreMsg = obtainMessage(MSG_BACKUP_RESTORE_STEP, task);
- sendMessage(restoreMsg);
- }
- }
- break;
- }
-
- case MSG_RUN_ADB_RESTORE:
- {
- // TODO: refactor full restore to be a looper-based state machine
- // similar to normal backup/restore.
- AdbRestoreParams params = (AdbRestoreParams)msg.obj;
- PerformAdbRestoreTask task = new PerformAdbRestoreTask(params.fd,
- params.curPassword, params.encryptPassword,
- params.observer, params.latch);
- (new Thread(task, "adb-restore")).start();
- break;
- }
-
- case MSG_RUN_CLEAR:
- {
- ClearParams params = (ClearParams)msg.obj;
- (new PerformClearTask(params.transport, params.packageInfo)).run();
- break;
- }
-
- case MSG_RETRY_CLEAR:
- {
- // reenqueues if the transport remains unavailable
- ClearRetryParams params = (ClearRetryParams)msg.obj;
- clearBackupData(params.transportName, params.packageName);
- break;
- }
-
- case MSG_RETRY_INIT:
- {
- synchronized (mQueueLock) {
- recordInitPendingLocked(msg.arg1 != 0, (String)msg.obj);
- mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
- mRunInitIntent);
- }
- break;
- }
-
- case MSG_RUN_GET_RESTORE_SETS:
- {
- // Like other async operations, this is entered with the wakelock held
- RestoreSet[] sets = null;
- RestoreGetSetsParams params = (RestoreGetSetsParams)msg.obj;
- try {
- sets = params.transport.getAvailableRestoreSets();
- // cache the result in the active session
- synchronized (params.session) {
- params.session.mRestoreSets = sets;
- }
- if (sets == null) EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
- } catch (Exception e) {
- Slog.e(TAG, "Error from transport getting set list: " + e.getMessage());
- } finally {
- if (params.observer != null) {
- try {
- params.observer.restoreSetsAvailable(sets);
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to report listing to observer");
- } catch (Exception e) {
- Slog.e(TAG, "Restore observer threw: " + e.getMessage());
- }
- }
-
- // Done: reset the session timeout clock
- removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
- sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT, TIMEOUT_RESTORE_INTERVAL);
-
- mWakelock.release();
- }
- break;
- }
-
- case MSG_BACKUP_OPERATION_TIMEOUT:
- case MSG_RESTORE_OPERATION_TIMEOUT:
- {
- Slog.d(TAG, "Timeout message received for token=" + Integer.toHexString(msg.arg1));
- handleCancel(msg.arg1, false);
- break;
- }
-
- case MSG_RESTORE_SESSION_TIMEOUT:
- {
- synchronized (BackupManagerService.this) {
- if (mActiveRestoreSession != null) {
- // Client app left the restore session dangling. We know that it
- // can't be in the middle of an actual restore operation because
- // the timeout is suspended while a restore is in progress. Clean
- // up now.
- Slog.w(TAG, "Restore session timed out; aborting");
- mActiveRestoreSession.markTimedOut();
- post(mActiveRestoreSession.new EndRestoreRunnable(
- BackupManagerService.this, mActiveRestoreSession));
- }
- }
- break;
- }
-
- case MSG_FULL_CONFIRMATION_TIMEOUT:
- {
- synchronized (mAdbBackupRestoreConfirmations) {
- AdbParams params = mAdbBackupRestoreConfirmations.get(msg.arg1);
- if (params != null) {
- Slog.i(TAG, "Full backup/restore timed out waiting for user confirmation");
-
- // Release the waiter; timeout == completion
- signalAdbBackupRestoreCompletion(params);
-
- // Remove the token from the set
- mAdbBackupRestoreConfirmations.delete(msg.arg1);
-
- // Report a timeout to the observer, if any
- if (params.observer != null) {
- try {
- params.observer.onTimeout();
- } catch (RemoteException e) {
- /* don't care if the app has gone away */
- }
- }
- } else {
- Slog.d(TAG, "couldn't find params for token " + msg.arg1);
- }
- }
- break;
- }
-
- case MSG_WIDGET_BROADCAST:
- {
- final Intent intent = (Intent) msg.obj;
- mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
- break;
- }
-
- case MSG_REQUEST_BACKUP:
- {
- BackupParams params = (BackupParams)msg.obj;
- if (MORE_DEBUG) {
- Slog.d(TAG, "MSG_REQUEST_BACKUP observer=" + params.observer);
- }
- ArrayList<BackupRequest> kvQueue = new ArrayList<>();
- for (String packageName : params.kvPackages) {
- kvQueue.add(new BackupRequest(packageName));
- }
- mBackupRunning = true;
- mWakelock.acquire();
-
- PerformBackupTask pbt = new PerformBackupTask(params.transport, params.dirName,
- kvQueue, null, params.observer, params.monitor, params.fullPackages, true,
- params.nonIncrementalBackup);
- Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt);
- sendMessage(pbtMessage);
- break;
- }
-
- case MSG_SCHEDULE_BACKUP_PACKAGE:
- {
- String pkgName = (String)msg.obj;
- if (MORE_DEBUG) {
- Slog.d(TAG, "MSG_SCHEDULE_BACKUP_PACKAGE " + pkgName);
- }
- dataChangedImpl(pkgName);
- break;
- }
- }
- }
- }
-
- // ----- Debug-only backup operation trace -----
- void addBackupTrace(String s) {
- if (DEBUG_BACKUP_TRACE) {
- synchronized (mBackupTrace) {
- mBackupTrace.add(s);
- }
- }
- }
-
- void clearBackupTrace() {
- if (DEBUG_BACKUP_TRACE) {
- synchronized (mBackupTrace) {
- mBackupTrace.clear();
- }
- }
- }
-
- // ----- Main service implementation -----
-
- public BackupManagerService(Context context, Trampoline parent, HandlerThread backupThread) {
- mContext = context;
- mPackageManager = context.getPackageManager();
- mPackageManagerBinder = AppGlobals.getPackageManager();
- mActivityManager = ActivityManager.getService();
-
- mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
- mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
-
- mBackupManagerBinder = Trampoline.asInterface(parent.asBinder());
-
- // spin up the backup/restore handler thread
- mBackupHandler = new BackupHandler(backupThread.getLooper());
-
- // Set up our bookkeeping
- final ContentResolver resolver = context.getContentResolver();
- mProvisioned = Settings.Global.getInt(resolver,
- Settings.Global.DEVICE_PROVISIONED, 0) != 0;
- mAutoRestore = Settings.Secure.getInt(resolver,
- Settings.Secure.BACKUP_AUTO_RESTORE, 1) != 0;
-
- mProvisionedObserver = new ProvisionedObserver(mBackupHandler);
- resolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
- false, mProvisionedObserver);
-
- // If Encrypted file systems is enabled or disabled, this call will return the
- // correct directory.
- mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
- mBaseStateDir.mkdirs();
- if (!SELinux.restorecon(mBaseStateDir)) {
- Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir);
- }
-
- // This dir on /cache is managed directly in init.rc
- mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup_stage");
-
- mPasswordVersion = 1; // unless we hear otherwise
- mPasswordVersionFile = new File(mBaseStateDir, "pwversion");
- if (mPasswordVersionFile.exists()) {
- FileInputStream fin = null;
- DataInputStream in = null;
- try {
- fin = new FileInputStream(mPasswordVersionFile);
- in = new DataInputStream(fin);
- mPasswordVersion = in.readInt();
- } catch (IOException e) {
- Slog.e(TAG, "Unable to read backup pw version");
- } finally {
- try {
- if (in != null) in.close();
- if (fin != null) fin.close();
- } catch (IOException e) {
- Slog.w(TAG, "Error closing pw version files");
- }
- }
- }
-
- mPasswordHashFile = new File(mBaseStateDir, "pwhash");
- if (mPasswordHashFile.exists()) {
- FileInputStream fin = null;
- DataInputStream in = null;
- try {
- fin = new FileInputStream(mPasswordHashFile);
- in = new DataInputStream(new BufferedInputStream(fin));
- // integer length of the salt array, followed by the salt,
- // then the hex pw hash string
- int saltLen = in.readInt();
- byte[] salt = new byte[saltLen];
- in.readFully(salt);
- mPasswordHash = in.readUTF();
- mPasswordSalt = salt;
- } catch (IOException e) {
- Slog.e(TAG, "Unable to read saved backup pw hash");
- } finally {
- try {
- if (in != null) in.close();
- if (fin != null) fin.close();
- } catch (IOException e) {
- Slog.w(TAG, "Unable to close streams");
- }
- }
- }
-
- // Alarm receivers for scheduled backups & initialization operations
- mRunBackupReceiver = new RunBackupReceiver();
- IntentFilter filter = new IntentFilter();
- filter.addAction(RUN_BACKUP_ACTION);
- context.registerReceiver(mRunBackupReceiver, filter,
- android.Manifest.permission.BACKUP, null);
-
- mRunInitReceiver = new RunInitializeReceiver();
- filter = new IntentFilter();
- filter.addAction(RUN_INITIALIZE_ACTION);
- context.registerReceiver(mRunInitReceiver, filter,
- android.Manifest.permission.BACKUP, null);
-
- Intent backupIntent = new Intent(RUN_BACKUP_ACTION);
- backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mRunBackupIntent = PendingIntent.getBroadcast(context, MSG_RUN_BACKUP, backupIntent, 0);
-
- Intent initIntent = new Intent(RUN_INITIALIZE_ACTION);
- initIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mRunInitIntent = PendingIntent.getBroadcast(context, 0, initIntent, 0);
-
- // Set up the backup-request journaling
- mJournalDir = new File(mBaseStateDir, "pending");
- mJournalDir.mkdirs(); // creates mBaseStateDir along the way
- mJournal = null; // will be created on first use
-
- mConstants = new BackupManagerConstants(mBackupHandler, mContext.getContentResolver());
-
- // Set up the various sorts of package tracking we do
- mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule");
- initPackageTracking();
-
- // Build our mapping of uid to backup client services. This implicitly
- // schedules a backup pass on the Package Manager metadata the first
- // time anything needs to be backed up.
- synchronized (mBackupParticipants) {
- addPackageParticipantsLocked(null);
- }
-
- // Set up our transport options and initialize the default transport
- // TODO: Don't create transports that we don't need to?
- SystemConfig systemConfig = SystemConfig.getInstance();
- Set<ComponentName> transportWhitelist = systemConfig.getBackupTransportWhitelist();
-
- String transport = Settings.Secure.getString(context.getContentResolver(),
- Settings.Secure.BACKUP_TRANSPORT);
- if (TextUtils.isEmpty(transport)) {
- transport = null;
- }
- String currentTransport = transport;
- if (DEBUG) Slog.v(TAG, "Starting with transport " + currentTransport);
-
- mTransportManager = new TransportManager(context, transportWhitelist, currentTransport,
- mTransportBoundListener, backupThread.getLooper());
- mTransportManager.registerAllTransports();
-
- // Now that we know about valid backup participants, parse any
- // leftover journal files into the pending backup set
- mBackupHandler.post(() -> parseLeftoverJournals());
-
- // Power management
- mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
- }
-
- private class RunBackupReceiver extends BroadcastReceiver {
- public void onReceive(Context context, Intent intent) {
- if (RUN_BACKUP_ACTION.equals(intent.getAction())) {
- synchronized (mQueueLock) {
- if (mPendingInits.size() > 0) {
- // If there are pending init operations, we process those
- // and then settle into the usual periodic backup schedule.
- if (MORE_DEBUG) Slog.v(TAG, "Init pending at scheduled backup");
- try {
- mAlarmManager.cancel(mRunInitIntent);
- mRunInitIntent.send();
- } catch (PendingIntent.CanceledException ce) {
- Slog.e(TAG, "Run init intent cancelled");
- // can't really do more than bail here
- }
- } else {
- // Don't run backups now if we're disabled or not yet
- // fully set up.
- if (mEnabled && mProvisioned) {
- if (!mBackupRunning) {
- if (DEBUG) Slog.v(TAG, "Running a backup pass");
-
- // Acquire the wakelock and pass it to the backup thread. it will
- // be released once backup concludes.
- mBackupRunning = true;
- mWakelock.acquire();
-
- Message msg = mBackupHandler.obtainMessage(MSG_RUN_BACKUP);
- mBackupHandler.sendMessage(msg);
- } else {
- Slog.i(TAG, "Backup time but one already running");
- }
- } else {
- Slog.w(TAG, "Backup pass but e=" + mEnabled + " p=" + mProvisioned);
- }
- }
- }
- }
- }
- }
-
- private class RunInitializeReceiver extends BroadcastReceiver {
- public void onReceive(Context context, Intent intent) {
- if (RUN_INITIALIZE_ACTION.equals(intent.getAction())) {
- // Snapshot the pending-init queue and work on that
- synchronized (mQueueLock) {
- String[] queue = mPendingInits.toArray(new String[mPendingInits.size()]);
- mPendingInits.clear();
-
- // Acquire the wakelock and pass it to the init thread. it will
- // be released once init concludes.
- mWakelock.acquire();
- mBackupHandler.post(new PerformInitializeTask(queue, null));
- }
- }
- }
- }
-
- private void initPackageTracking() {
- if (MORE_DEBUG) Slog.v(TAG, "` tracking");
-
- // Remember our ancestral dataset
- mTokenFile = new File(mBaseStateDir, "ancestral");
- try (DataInputStream tokenStream = new DataInputStream(new BufferedInputStream(
- new FileInputStream(mTokenFile)))) {
- int version = tokenStream.readInt();
- if (version == CURRENT_ANCESTRAL_RECORD_VERSION) {
- mAncestralToken = tokenStream.readLong();
- mCurrentToken = tokenStream.readLong();
-
- int numPackages = tokenStream.readInt();
- if (numPackages >= 0) {
- mAncestralPackages = new HashSet<>();
- for (int i = 0; i < numPackages; i++) {
- String pkgName = tokenStream.readUTF();
- mAncestralPackages.add(pkgName);
- }
- }
- }
- } catch (FileNotFoundException fnf) {
- // Probably innocuous
- Slog.v(TAG, "No ancestral data");
- } catch (IOException e) {
- Slog.w(TAG, "Unable to read token file", e);
- }
-
- // Keep a log of what apps we've ever backed up. Because we might have
- // rebooted in the middle of an operation that was removing something from
- // this log, we sanity-check its contents here and reconstruct it.
- mEverStored = new File(mBaseStateDir, "processed");
-
- // If there are previous contents, parse them out then start a new
- // file to continue the recordkeeping.
- if (mEverStored.exists()) {
- try (DataInputStream in = new DataInputStream(
- new BufferedInputStream(new FileInputStream(mEverStored)))) {
-
- // Loop until we hit EOF
- while (true) {
- String pkg = in.readUTF();
- mEverStoredApps.add(pkg);
- if (MORE_DEBUG) Slog.v(TAG, " + " + pkg);
- }
- } catch (EOFException e) {
- // Done
- } catch (IOException e) {
- Slog.e(TAG, "Error in processed file", e);
- }
- }
-
- synchronized (mQueueLock) {
- // Resume the full-data backup queue
- mFullBackupQueue = readFullBackupSchedule();
- }
-
- // Register for broadcasts about package install, etc., so we can
- // update the provider list.
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- filter.addDataScheme("package");
- mContext.registerReceiver(mBroadcastReceiver, filter);
- // Register for events related to sdcard installation.
- IntentFilter sdFilter = new IntentFilter();
- sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
- sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
- mContext.registerReceiver(mBroadcastReceiver, sdFilter);
- }
-
- private ArrayList<FullBackupEntry> readFullBackupSchedule() {
- boolean changed = false;
- ArrayList<FullBackupEntry> schedule = null;
- List<PackageInfo> apps =
- PackageManagerBackupAgent.getStorableApplications(mPackageManager);
-
- if (mFullBackupScheduleFile.exists()) {
- FileInputStream fstream = null;
- BufferedInputStream bufStream = null;
- DataInputStream in = null;
- try {
- fstream = new FileInputStream(mFullBackupScheduleFile);
- bufStream = new BufferedInputStream(fstream);
- in = new DataInputStream(bufStream);
-
- int version = in.readInt();
- if (version != SCHEDULE_FILE_VERSION) {
- Slog.e(TAG, "Unknown backup schedule version " + version);
- return null;
- }
-
- final int N = in.readInt();
- schedule = new ArrayList<FullBackupEntry>(N);
-
- // HashSet instead of ArraySet specifically because we want the eventual
- // lookups against O(hundreds) of entries to be as fast as possible, and
- // we discard the set immediately after the scan so the extra memory
- // overhead is transient.
- HashSet<String> foundApps = new HashSet<String>(N);
-
- for (int i = 0; i < N; i++) {
- String pkgName = in.readUTF();
- long lastBackup = in.readLong();
- foundApps.add(pkgName); // all apps that we've addressed already
- try {
- PackageInfo pkg = mPackageManager.getPackageInfo(pkgName, 0);
- if (appGetsFullBackup(pkg)
- && appIsEligibleForBackup(pkg.applicationInfo, mPackageManager)) {
- schedule.add(new FullBackupEntry(pkgName, lastBackup));
- } else {
- if (DEBUG) {
- Slog.i(TAG, "Package " + pkgName
- + " no longer eligible for full backup");
- }
- }
- } catch (NameNotFoundException e) {
- if (DEBUG) {
- Slog.i(TAG, "Package " + pkgName
- + " not installed; dropping from full backup");
- }
- }
- }
-
- // New apps can arrive "out of band" via OTA and similar, so we also need to
- // scan to make sure that we're tracking all full-backup candidates properly
- for (PackageInfo app : apps) {
- if (appGetsFullBackup(app)
- && appIsEligibleForBackup(app.applicationInfo, mPackageManager)) {
- if (!foundApps.contains(app.packageName)) {
- if (MORE_DEBUG) {
- Slog.i(TAG, "New full backup app " + app.packageName + " found");
- }
- schedule.add(new FullBackupEntry(app.packageName, 0));
- changed = true;
- }
- }
- }
-
- Collections.sort(schedule);
- } catch (Exception e) {
- Slog.e(TAG, "Unable to read backup schedule", e);
- mFullBackupScheduleFile.delete();
- schedule = null;
- } finally {
- IoUtils.closeQuietly(in);
- IoUtils.closeQuietly(bufStream);
- IoUtils.closeQuietly(fstream);
- }
- }
-
- if (schedule == null) {
- // no prior queue record, or unable to read it. Set up the queue
- // from scratch.
- changed = true;
- schedule = new ArrayList<FullBackupEntry>(apps.size());
- for (PackageInfo info : apps) {
- if (appGetsFullBackup(info)
- && appIsEligibleForBackup(info.applicationInfo, mPackageManager)) {
- schedule.add(new FullBackupEntry(info.packageName, 0));
- }
- }
- }
-
- if (changed) {
- writeFullBackupScheduleAsync();
- }
- return schedule;
- }
-
- Runnable mFullBackupScheduleWriter = new Runnable() {
- @Override public void run() {
- synchronized (mQueueLock) {
- try {
- ByteArrayOutputStream bufStream = new ByteArrayOutputStream(4096);
- DataOutputStream bufOut = new DataOutputStream(bufStream);
- bufOut.writeInt(SCHEDULE_FILE_VERSION);
-
- // version 1:
- //
- // [int] # of packages in the queue = N
- // N * {
- // [utf8] package name
- // [long] last backup time for this package
- // }
- int N = mFullBackupQueue.size();
- bufOut.writeInt(N);
-
- for (int i = 0; i < N; i++) {
- FullBackupEntry entry = mFullBackupQueue.get(i);
- bufOut.writeUTF(entry.packageName);
- bufOut.writeLong(entry.lastBackup);
- }
- bufOut.flush();
-
- AtomicFile af = new AtomicFile(mFullBackupScheduleFile);
- FileOutputStream out = af.startWrite();
- out.write(bufStream.toByteArray());
- af.finishWrite(out);
- } catch (Exception e) {
- Slog.e(TAG, "Unable to write backup schedule!", e);
- }
- }
- }
- };
-
- private void writeFullBackupScheduleAsync() {
- mBackupHandler.removeCallbacks(mFullBackupScheduleWriter);
- mBackupHandler.post(mFullBackupScheduleWriter);
- }
-
- private void parseLeftoverJournals() {
- for (File f : mJournalDir.listFiles()) {
- if (mJournal == null || f.compareTo(mJournal) != 0) {
- // This isn't the current journal, so it must be a leftover. Read
- // out the package names mentioned there and schedule them for
- // backup.
- DataInputStream in = null;
- try {
- Slog.i(TAG, "Found stale backup journal, scheduling");
- // Journals will tend to be on the order of a few kilobytes(around 4k), hence,
- // setting the buffer size to 8192.
- InputStream bufferedInputStream = new BufferedInputStream(
- new FileInputStream(f), 8192);
- in = new DataInputStream(bufferedInputStream);
- while (true) {
- String packageName = in.readUTF();
- if (MORE_DEBUG) Slog.i(TAG, " " + packageName);
- dataChangedImpl(packageName);
- }
- } catch (EOFException e) {
- // no more data; we're done
- } catch (Exception e) {
- Slog.e(TAG, "Can't read " + f, e);
- } finally {
- // close/delete the file
- try { if (in != null) in.close(); } catch (IOException e) {}
- f.delete();
- }
- }
- }
- }
-
- private SecretKey buildPasswordKey(String algorithm, String pw, byte[] salt, int rounds) {
- return buildCharArrayKey(algorithm, pw.toCharArray(), salt, rounds);
- }
-
- private SecretKey buildCharArrayKey(String algorithm, char[] pwArray, byte[] salt, int rounds) {
- try {
- SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
- KeySpec ks = new PBEKeySpec(pwArray, salt, rounds, PBKDF2_KEY_SIZE);
- return keyFactory.generateSecret(ks);
- } catch (InvalidKeySpecException e) {
- Slog.e(TAG, "Invalid key spec for PBKDF2!");
- } catch (NoSuchAlgorithmException e) {
- Slog.e(TAG, "PBKDF2 unavailable!");
- }
- return null;
- }
-
- private String buildPasswordHash(String algorithm, String pw, byte[] salt, int rounds) {
- SecretKey key = buildPasswordKey(algorithm, pw, salt, rounds);
- if (key != null) {
- return byteArrayToHex(key.getEncoded());
- }
- return null;
- }
-
- private String byteArrayToHex(byte[] data) {
- StringBuilder buf = new StringBuilder(data.length * 2);
- for (int i = 0; i < data.length; i++) {
- buf.append(Byte.toHexString(data[i], true));
- }
- return buf.toString();
- }
-
- private byte[] hexToByteArray(String digits) {
- final int bytes = digits.length() / 2;
- if (2*bytes != digits.length()) {
- throw new IllegalArgumentException("Hex string must have an even number of digits");
- }
-
- byte[] result = new byte[bytes];
- for (int i = 0; i < digits.length(); i += 2) {
- result[i/2] = (byte) Integer.parseInt(digits.substring(i, i+2), 16);
- }
- return result;
- }
-
- private byte[] makeKeyChecksum(String algorithm, byte[] pwBytes, byte[] salt, int rounds) {
- char[] mkAsChar = new char[pwBytes.length];
- for (int i = 0; i < pwBytes.length; i++) {
- mkAsChar[i] = (char) pwBytes[i];
- }
-
- Key checksum = buildCharArrayKey(algorithm, mkAsChar, salt, rounds);
- return checksum.getEncoded();
- }
-
- // Used for generating random salts or passwords
- private byte[] randomBytes(int bits) {
- byte[] array = new byte[bits / 8];
- mRng.nextBytes(array);
- return array;
- }
-
- boolean passwordMatchesSaved(String algorithm, String candidatePw, int rounds) {
- if (mPasswordHash == null) {
- // no current password case -- require that 'currentPw' be null or empty
- if (candidatePw == null || "".equals(candidatePw)) {
- return true;
- } // else the non-empty candidate does not match the empty stored pw
- } else {
- // hash the stated current pw and compare to the stored one
- if (candidatePw != null && candidatePw.length() > 0) {
- String currentPwHash = buildPasswordHash(algorithm, candidatePw, mPasswordSalt, rounds);
- if (mPasswordHash.equalsIgnoreCase(currentPwHash)) {
- // candidate hash matches the stored hash -- the password matches
- return true;
- }
- } // else the stored pw is nonempty but the candidate is empty; no match
- }
- return false;
- }
-
- @Override
- public boolean setBackupPassword(String currentPw, String newPw) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "setBackupPassword");
-
- // When processing v1 passwords we may need to try two different PBKDF2 checksum regimes
- final boolean pbkdf2Fallback = (mPasswordVersion < BACKUP_PW_FILE_VERSION);
-
- // If the supplied pw doesn't hash to the the saved one, fail. The password
- // might be caught in the legacy crypto mismatch; verify that too.
- if (!passwordMatchesSaved(PBKDF_CURRENT, currentPw, PBKDF2_HASH_ROUNDS)
- && !(pbkdf2Fallback && passwordMatchesSaved(PBKDF_FALLBACK,
- currentPw, PBKDF2_HASH_ROUNDS))) {
- return false;
- }
-
- // Snap up to current on the pw file version
- mPasswordVersion = BACKUP_PW_FILE_VERSION;
- FileOutputStream pwFout = null;
- DataOutputStream pwOut = null;
- try {
- pwFout = new FileOutputStream(mPasswordVersionFile);
- pwOut = new DataOutputStream(pwFout);
- pwOut.writeInt(mPasswordVersion);
- } catch (IOException e) {
- Slog.e(TAG, "Unable to write backup pw version; password not changed");
- return false;
- } finally {
- try {
- if (pwOut != null) pwOut.close();
- if (pwFout != null) pwFout.close();
- } catch (IOException e) {
- Slog.w(TAG, "Unable to close pw version record");
- }
- }
-
- // Clearing the password is okay
- if (newPw == null || newPw.isEmpty()) {
- if (mPasswordHashFile.exists()) {
- if (!mPasswordHashFile.delete()) {
- // Unable to delete the old pw file, so fail
- Slog.e(TAG, "Unable to clear backup password");
- return false;
- }
- }
- mPasswordHash = null;
- mPasswordSalt = null;
- return true;
- }
-
- try {
- // Okay, build the hash of the new backup password
- byte[] salt = randomBytes(PBKDF2_SALT_SIZE);
- String newPwHash = buildPasswordHash(PBKDF_CURRENT, newPw, salt, PBKDF2_HASH_ROUNDS);
-
- OutputStream pwf = null, buffer = null;
- DataOutputStream out = null;
- try {
- pwf = new FileOutputStream(mPasswordHashFile);
- buffer = new BufferedOutputStream(pwf);
- out = new DataOutputStream(buffer);
- // integer length of the salt array, followed by the salt,
- // then the hex pw hash string
- out.writeInt(salt.length);
- out.write(salt);
- out.writeUTF(newPwHash);
- out.flush();
- mPasswordHash = newPwHash;
- mPasswordSalt = salt;
- return true;
- } finally {
- if (out != null) out.close();
- if (buffer != null) buffer.close();
- if (pwf != null) pwf.close();
- }
- } catch (IOException e) {
- Slog.e(TAG, "Unable to set backup password");
- }
- return false;
- }
-
- @Override
- public boolean hasBackupPassword() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "hasBackupPassword");
-
- return mPasswordHash != null && mPasswordHash.length() > 0;
- }
-
- private boolean backupPasswordMatches(String currentPw) {
- if (hasBackupPassword()) {
- final boolean pbkdf2Fallback = (mPasswordVersion < BACKUP_PW_FILE_VERSION);
- if (!passwordMatchesSaved(PBKDF_CURRENT, currentPw, PBKDF2_HASH_ROUNDS)
- && !(pbkdf2Fallback && passwordMatchesSaved(PBKDF_FALLBACK,
- currentPw, PBKDF2_HASH_ROUNDS))) {
- if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
- return false;
- }
- }
- return true;
- }
-
- // Maintain persistent state around whether need to do an initialize operation.
- // Must be called with the queue lock held.
- void recordInitPendingLocked(boolean isPending, String transportName) {
- if (MORE_DEBUG) Slog.i(TAG, "recordInitPendingLocked: " + isPending
- + " on transport " + transportName);
- mBackupHandler.removeMessages(MSG_RETRY_INIT);
-
- try {
- IBackupTransport transport = mTransportManager.getTransportBinder(transportName);
- if (transport != null) {
- String transportDirName = transport.transportDirName();
- File stateDir = new File(mBaseStateDir, transportDirName);
- File initPendingFile = new File(stateDir, INIT_SENTINEL_FILE_NAME);
-
- if (isPending) {
- // We need an init before we can proceed with sending backup data.
- // Record that with an entry in our set of pending inits, as well as
- // journaling it via creation of a sentinel file.
- mPendingInits.add(transportName);
- try {
- (new FileOutputStream(initPendingFile)).close();
- } catch (IOException ioe) {
- // Something is badly wrong with our permissions; just try to move on
- }
- } else {
- // No more initialization needed; wipe the journal and reset our state.
- initPendingFile.delete();
- mPendingInits.remove(transportName);
- }
- return; // done; don't fall through to the error case
- }
- } catch (Exception e) {
- // transport threw when asked its name; fall through to the lookup-failed case
- Slog.e(TAG, "Transport " + transportName + " failed to report name: "
- + e.getMessage());
- }
-
- // The named transport doesn't exist or threw. This operation is
- // important, so we record the need for a an init and post a message
- // to retry the init later.
- if (isPending) {
- mPendingInits.add(transportName);
- mBackupHandler.sendMessageDelayed(
- mBackupHandler.obtainMessage(MSG_RETRY_INIT,
- (isPending ? 1 : 0),
- 0,
- transportName),
- TRANSPORT_RETRY_INTERVAL);
- }
- }
-
- // Reset all of our bookkeeping, in response to having been told that
- // the backend data has been wiped [due to idle expiry, for example],
- // so we must re-upload all saved settings.
- void resetBackupState(File stateFileDir) {
- synchronized (mQueueLock) {
- // Wipe the "what we've ever backed up" tracking
- mEverStoredApps.clear();
- mEverStored.delete();
-
- mCurrentToken = 0;
- writeRestoreTokens();
-
- // Remove all the state files
- for (File sf : stateFileDir.listFiles()) {
- // ... but don't touch the needs-init sentinel
- if (!sf.getName().equals(INIT_SENTINEL_FILE_NAME)) {
- sf.delete();
- }
- }
- }
-
- // Enqueue a new backup of every participant
- synchronized (mBackupParticipants) {
- final int N = mBackupParticipants.size();
- for (int i=0; i<N; i++) {
- HashSet<String> participants = mBackupParticipants.valueAt(i);
- if (participants != null) {
- for (String packageName : participants) {
- dataChangedImpl(packageName);
- }
- }
- }
- }
- }
-
- private TransportManager.TransportBoundListener mTransportBoundListener =
- new TransportManager.TransportBoundListener() {
- @Override
- public boolean onTransportBound(IBackupTransport transport) {
- // If the init sentinel file exists, we need to be sure to perform the init
- // as soon as practical. We also create the state directory at registration
- // time to ensure it's present from the outset.
- String name = null;
- try {
- name = transport.name();
- String transportDirName = transport.transportDirName();
- File stateDir = new File(mBaseStateDir, transportDirName);
- stateDir.mkdirs();
-
- File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME);
- if (initSentinel.exists()) {
- synchronized (mQueueLock) {
- mPendingInits.add(name);
-
- // TODO: pick a better starting time than now + 1 minute
- long delay = 1000 * 60; // one minute, in milliseconds
- mAlarmManager.set(AlarmManager.RTC_WAKEUP,
- System.currentTimeMillis() + delay, mRunInitIntent);
- }
- }
- return true;
- } catch (Exception e) {
- // the transport threw when asked its file naming prefs; declare it invalid
- Slog.w(TAG, "Failed to regiser transport: " + name);
- return false;
- }
- }
- };
-
- // ----- Track installation/removal of packages -----
- BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- public void onReceive(Context context, Intent intent) {
- if (MORE_DEBUG) Slog.d(TAG, "Received broadcast " + intent);
-
- String action = intent.getAction();
- boolean replacing = false;
- boolean added = false;
- boolean changed = false;
- Bundle extras = intent.getExtras();
- String pkgList[] = null;
- if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
- Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
- Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
- Uri uri = intent.getData();
- if (uri == null) {
- return;
- }
- final String pkgName = uri.getSchemeSpecificPart();
- if (pkgName != null) {
- pkgList = new String[] { pkgName };
- }
- changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
-
- // At package-changed we only care about looking at new transport states
- if (changed) {
- final String[] components =
- intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
-
- if (MORE_DEBUG) {
- Slog.i(TAG, "Package " + pkgName + " changed; rechecking");
- for (int i = 0; i < components.length; i++) {
- Slog.i(TAG, " * " + components[i]);
- }
- }
-
- mBackupHandler.post(
- () -> mTransportManager.onPackageChanged(pkgName, components));
- return; // nothing more to do in the PACKAGE_CHANGED case
- }
-
- added = Intent.ACTION_PACKAGE_ADDED.equals(action);
- replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
- } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
- added = true;
- pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
- } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
- added = false;
- pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
- }
-
- if (pkgList == null || pkgList.length == 0) {
- return;
- }
-
- final int uid = extras.getInt(Intent.EXTRA_UID);
- if (added) {
- synchronized (mBackupParticipants) {
- if (replacing) {
- // This is the package-replaced case; we just remove the entry
- // under the old uid and fall through to re-add. If an app
- // just added key/value backup participation, this picks it up
- // as a known participant.
- removePackageParticipantsLocked(pkgList, uid);
- }
- addPackageParticipantsLocked(pkgList);
- }
- // If they're full-backup candidates, add them there instead
- final long now = System.currentTimeMillis();
- for (final String packageName : pkgList) {
- try {
- PackageInfo app = mPackageManager.getPackageInfo(packageName, 0);
- if (appGetsFullBackup(app)
- && appIsEligibleForBackup(app.applicationInfo, mPackageManager)) {
- enqueueFullBackup(packageName, now);
- scheduleNextFullBackupJob(0);
- } else {
- // The app might have just transitioned out of full-data into
- // doing key/value backups, or might have just disabled backups
- // entirely. Make sure it is no longer in the full-data queue.
- synchronized (mQueueLock) {
- dequeueFullBackupLocked(packageName);
- }
- writeFullBackupScheduleAsync();
- }
-
- mBackupHandler.post(
- () -> mTransportManager.onPackageAdded(packageName));
-
- } catch (NameNotFoundException e) {
- // doesn't really exist; ignore it
- if (DEBUG) {
- Slog.w(TAG, "Can't resolve new app " + packageName);
- }
- }
- }
-
- // Whenever a package is added or updated we need to update
- // the package metadata bookkeeping.
- dataChangedImpl(PACKAGE_MANAGER_SENTINEL);
- } else {
- if (replacing) {
- // The package is being updated. We'll receive a PACKAGE_ADDED shortly.
- } else {
- // Outright removal. In the full-data case, the app will be dropped
- // from the queue when its (now obsolete) name comes up again for
- // backup.
- synchronized (mBackupParticipants) {
- removePackageParticipantsLocked(pkgList, uid);
- }
- }
- for (final String pkgName : pkgList) {
- mBackupHandler.post(
- () -> mTransportManager.onPackageRemoved(pkgName));
- }
- }
- }
- };
-
- // Add the backup agents in the given packages to our set of known backup participants.
- // If 'packageNames' is null, adds all backup agents in the whole system.
- void addPackageParticipantsLocked(String[] packageNames) {
- // Look for apps that define the android:backupAgent attribute
- List<PackageInfo> targetApps = allAgentPackages();
- if (packageNames != null) {
- if (MORE_DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: #" + packageNames.length);
- for (String packageName : packageNames) {
- addPackageParticipantsLockedInner(packageName, targetApps);
- }
- } else {
- if (MORE_DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: all");
- addPackageParticipantsLockedInner(null, targetApps);
- }
- }
-
- private void addPackageParticipantsLockedInner(String packageName,
- List<PackageInfo> targetPkgs) {
- if (MORE_DEBUG) {
- Slog.v(TAG, "Examining " + packageName + " for backup agent");
- }
-
- for (PackageInfo pkg : targetPkgs) {
- if (packageName == null || pkg.packageName.equals(packageName)) {
- int uid = pkg.applicationInfo.uid;
- HashSet<String> set = mBackupParticipants.get(uid);
- if (set == null) {
- set = new HashSet<>();
- mBackupParticipants.put(uid, set);
- }
- set.add(pkg.packageName);
- if (MORE_DEBUG) Slog.v(TAG, "Agent found; added");
-
- // Schedule a backup for it on general principles
- if (MORE_DEBUG) Slog.i(TAG, "Scheduling backup for new app " + pkg.packageName);
- Message msg = mBackupHandler
- .obtainMessage(MSG_SCHEDULE_BACKUP_PACKAGE, pkg.packageName);
- mBackupHandler.sendMessage(msg);
- }
- }
- }
-
- // Remove the given packages' entries from our known active set.
- void removePackageParticipantsLocked(String[] packageNames, int oldUid) {
- if (packageNames == null) {
- Slog.w(TAG, "removePackageParticipants with null list");
- return;
- }
-
- if (MORE_DEBUG) Slog.v(TAG, "removePackageParticipantsLocked: uid=" + oldUid
- + " #" + packageNames.length);
- for (String pkg : packageNames) {
- // Known previous UID, so we know which package set to check
- HashSet<String> set = mBackupParticipants.get(oldUid);
- if (set != null && set.contains(pkg)) {
- removePackageFromSetLocked(set, pkg);
- if (set.isEmpty()) {
- if (MORE_DEBUG) Slog.v(TAG, " last one of this uid; purging set");
- mBackupParticipants.remove(oldUid);
- }
- }
- }
- }
-
- private void removePackageFromSetLocked(final HashSet<String> set,
- final String packageName) {
- if (set.contains(packageName)) {
- // Found it. Remove this one package from the bookkeeping, and
- // if it's the last participating app under this uid we drop the
- // (now-empty) set as well.
- // Note that we deliberately leave it 'known' in the "ever backed up"
- // bookkeeping so that its current-dataset data will be retrieved
- // if the app is subsequently reinstalled
- if (MORE_DEBUG) Slog.v(TAG, " removing participant " + packageName);
- set.remove(packageName);
- mPendingBackups.remove(packageName);
- }
- }
-
- // Returns the set of all applications that define an android:backupAgent attribute
- List<PackageInfo> allAgentPackages() {
- // !!! TODO: cache this and regenerate only when necessary
- int flags = PackageManager.GET_SIGNATURES;
- List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
- int N = packages.size();
- for (int a = N-1; a >= 0; a--) {
- PackageInfo pkg = packages.get(a);
- try {
- ApplicationInfo app = pkg.applicationInfo;
- if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
- || app.backupAgentName == null
- || (app.flags&ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0) {
- packages.remove(a);
- }
- else {
- // we will need the shared library path, so look that up and store it here.
- // This is used implicitly when we pass the PackageInfo object off to
- // the Activity Manager to launch the app for backup/restore purposes.
- app = mPackageManager.getApplicationInfo(pkg.packageName,
- PackageManager.GET_SHARED_LIBRARY_FILES);
- pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles;
- }
- } catch (NameNotFoundException e) {
- packages.remove(a);
- }
- }
- return packages;
- }
-
- // Called from the backup tasks: record that the given app has been successfully
- // backed up at least once. This includes both key/value and full-data backups
- // through the transport.
- void logBackupComplete(String packageName) {
- if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) return;
-
- synchronized (mEverStoredApps) {
- if (!mEverStoredApps.add(packageName)) return;
-
- RandomAccessFile out = null;
- try {
- out = new RandomAccessFile(mEverStored, "rws");
- out.seek(out.length());
- out.writeUTF(packageName);
- } catch (IOException e) {
- Slog.e(TAG, "Can't log backup of " + packageName + " to " + mEverStored);
- } finally {
- try { if (out != null) out.close(); } catch (IOException e) {}
- }
- }
- }
-
- // Persistently record the current and ancestral backup tokens as well
- // as the set of packages with data [supposedly] available in the
- // ancestral dataset.
- void writeRestoreTokens() {
- try {
- RandomAccessFile af = new RandomAccessFile(mTokenFile, "rwd");
-
- // First, the version number of this record, for futureproofing
- af.writeInt(CURRENT_ANCESTRAL_RECORD_VERSION);
-
- // Write the ancestral and current tokens
- af.writeLong(mAncestralToken);
- af.writeLong(mCurrentToken);
-
- // Now write the set of ancestral packages
- if (mAncestralPackages == null) {
- af.writeInt(-1);
- } else {
- af.writeInt(mAncestralPackages.size());
- if (DEBUG) Slog.v(TAG, "Ancestral packages: " + mAncestralPackages.size());
- for (String pkgName : mAncestralPackages) {
- af.writeUTF(pkgName);
- if (MORE_DEBUG) Slog.v(TAG, " " + pkgName);
- }
- }
- af.close();
- } catch (IOException e) {
- Slog.w(TAG, "Unable to write token file:", e);
- }
- }
-
- // What name is this transport registered under...?
- private String getTransportName(IBackupTransport transport) {
- if (MORE_DEBUG) {
- Slog.v(TAG, "Searching for transport name of " + transport);
- }
- return mTransportManager.getTransportName(transport);
- }
-
- // fire off a backup agent, blocking until it attaches or times out
- @Override
- public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) {
- IBackupAgent agent = null;
- synchronized(mAgentConnectLock) {
- mConnecting = true;
- mConnectedAgent = null;
- try {
- if (mActivityManager.bindBackupAgent(app.packageName, mode,
- UserHandle.USER_OWNER)) {
- Slog.d(TAG, "awaiting agent for " + app);
-
- // success; wait for the agent to arrive
- // only wait 10 seconds for the bind to happen
- long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
- while (mConnecting && mConnectedAgent == null
- && (System.currentTimeMillis() < timeoutMark)) {
- try {
- mAgentConnectLock.wait(5000);
- } catch (InterruptedException e) {
- // just bail
- Slog.w(TAG, "Interrupted: " + e);
- mConnecting = false;
- mConnectedAgent = null;
- }
- }
-
- // if we timed out with no connect, abort and move on
- if (mConnecting == true) {
- Slog.w(TAG, "Timeout waiting for agent " + app);
- mConnectedAgent = null;
- }
- if (DEBUG) Slog.i(TAG, "got agent " + mConnectedAgent);
- agent = mConnectedAgent;
- }
- } catch (RemoteException e) {
- // can't happen - ActivityManager is local
- }
- }
- if (agent == null) {
- try {
- mActivityManager.clearPendingBackup();
- } catch (RemoteException e) {
- // can't happen - ActivityManager is local
- }
- }
- return agent;
- }
-
- // clear an application's data, blocking until the operation completes or times out
- void clearApplicationDataSynchronous(String packageName) {
- // Don't wipe packages marked allowClearUserData=false
- try {
- PackageInfo info = mPackageManager.getPackageInfo(packageName, 0);
- if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) {
- if (MORE_DEBUG) Slog.i(TAG, "allowClearUserData=false so not wiping "
- + packageName);
- return;
- }
- } catch (NameNotFoundException e) {
- Slog.w(TAG, "Tried to clear data for " + packageName + " but not found");
- return;
- }
-
- ClearDataObserver observer = new ClearDataObserver();
-
- synchronized(mClearDataLock) {
- mClearingData = true;
- try {
- mActivityManager.clearApplicationUserData(packageName, observer, 0);
- } catch (RemoteException e) {
- // can't happen because the activity manager is in this process
- }
-
- // only wait 10 seconds for the clear data to happen
- long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
- while (mClearingData && (System.currentTimeMillis() < timeoutMark)) {
- try {
- mClearDataLock.wait(5000);
- } catch (InterruptedException e) {
- // won't happen, but still.
- mClearingData = false;
- }
- }
- }
- }
-
- class ClearDataObserver extends IPackageDataObserver.Stub {
- public void onRemoveCompleted(String packageName, boolean succeeded) {
- synchronized(mClearDataLock) {
- mClearingData = false;
- mClearDataLock.notifyAll();
- }
- }
- }
-
- // Get the restore-set token for the best-available restore set for this package:
- // the active set if possible, else the ancestral one. Returns zero if none available.
- @Override
- public long getAvailableRestoreToken(String packageName) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "getAvailableRestoreToken");
-
- long token = mAncestralToken;
- synchronized (mQueueLock) {
- if (mCurrentToken != 0 && mEverStoredApps.contains(packageName)) {
- if (MORE_DEBUG) {
- Slog.i(TAG, "App in ever-stored, so using current token");
- }
- token = mCurrentToken;
- }
- }
- if (MORE_DEBUG) Slog.i(TAG, "getAvailableRestoreToken() == " + token);
- return token;
- }
-
- @Override
- public int requestBackup(String[] packages, IBackupObserver observer, int flags) {
- return requestBackup(packages, observer, null, flags);
- }
-
- @Override
- public int requestBackup(String[] packages, IBackupObserver observer,
- IBackupManagerMonitor monitor, int flags) {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "requestBackup");
-
- if (packages == null || packages.length < 1) {
- Slog.e(TAG, "No packages named for backup request");
- sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
- monitor = monitorEvent(monitor, BackupManagerMonitor.LOG_EVENT_ID_NO_PACKAGES,
- null, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null);
- throw new IllegalArgumentException("No packages are provided for backup");
- }
-
- if (!mEnabled || !mProvisioned) {
- Slog.i(TAG, "Backup requested but e=" + mEnabled + " p=" +mProvisioned);
- sendBackupFinished(observer, BackupManager.ERROR_BACKUP_NOT_ALLOWED);
- final int logTag = mProvisioned
- ? BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED
- : BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED;
- monitor = monitorEvent(monitor, logTag, null,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
- return BackupManager.ERROR_BACKUP_NOT_ALLOWED;
- }
-
- IBackupTransport transport = mTransportManager.getCurrentTransportBinder();
- if (transport == null) {
- sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
- monitor = monitorEvent(monitor, BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL,
- null, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null);
- return BackupManager.ERROR_TRANSPORT_ABORTED;
- }
-
- ArrayList<String> fullBackupList = new ArrayList<>();
- ArrayList<String> kvBackupList = new ArrayList<>();
- for (String packageName : packages) {
- if (PACKAGE_MANAGER_SENTINEL.equals(packageName)) {
- kvBackupList.add(packageName);
- continue;
- }
- try {
- PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
- PackageManager.GET_SIGNATURES);
- if (!appIsEligibleForBackup(packageInfo.applicationInfo, mPackageManager)) {
- sendBackupOnPackageResult(observer, packageName,
- BackupManager.ERROR_BACKUP_NOT_ALLOWED);
- continue;
- }
- if (appGetsFullBackup(packageInfo)) {
- fullBackupList.add(packageInfo.packageName);
- } else {
- kvBackupList.add(packageInfo.packageName);
- }
- } catch (NameNotFoundException e) {
- sendBackupOnPackageResult(observer, packageName,
- BackupManager.ERROR_PACKAGE_NOT_FOUND);
- }
- }
- EventLog.writeEvent(EventLogTags.BACKUP_REQUESTED, packages.length, kvBackupList.size(),
- fullBackupList.size());
- if (MORE_DEBUG) {
- Slog.i(TAG, "Backup requested for " + packages.length + " packages, of them: " +
- fullBackupList.size() + " full backups, " + kvBackupList.size() + " k/v backups");
- }
-
- String dirName;
- try {
- dirName = transport.transportDirName();
- } catch (Exception e) {
- Slog.e(TAG, "Transport unavailable while attempting backup: " + e.getMessage());
- sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
- return BackupManager.ERROR_TRANSPORT_ABORTED;
- }
-
- boolean nonIncrementalBackup = (flags & BackupManager.FLAG_NON_INCREMENTAL_BACKUP) != 0;
-
- Message msg = mBackupHandler.obtainMessage(MSG_REQUEST_BACKUP);
- msg.obj = new BackupParams(transport, dirName, kvBackupList, fullBackupList, observer,
- monitor, true, nonIncrementalBackup);
- mBackupHandler.sendMessage(msg);
- return BackupManager.SUCCESS;
- }
-
- // Cancel all running backups.
- @Override
- public void cancelBackups(){
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "cancelBackups");
- if (MORE_DEBUG) {
- Slog.i(TAG, "cancelBackups() called.");
- }
- final long oldToken = Binder.clearCallingIdentity();
- try {
- List<Integer> operationsToCancel = new ArrayList<>();
- synchronized (mCurrentOpLock) {
- for (int i = 0; i < mCurrentOperations.size(); i++) {
- Operation op = mCurrentOperations.valueAt(i);
- int token = mCurrentOperations.keyAt(i);
- if (op.type == OP_TYPE_BACKUP) {
- operationsToCancel.add(token);
- }
- }
- }
- for (Integer token : operationsToCancel) {
- handleCancel(token, true /* cancelAll */);
- }
- // We don't want the backup jobs to kick in any time soon.
- // Reschedules them to run in the distant future.
- KeyValueBackupJob.schedule(mContext, BUSY_BACKOFF_MIN_MILLIS, mConstants);
- FullBackupJob.schedule(mContext, 2 * BUSY_BACKOFF_MIN_MILLIS, mConstants);
- } finally {
- Binder.restoreCallingIdentity(oldToken);
- }
- }
-
- @Override
- public void prepareOperationTimeout(int token, long interval, BackupRestoreTask callback,
- int operationType) {
- if (operationType != OP_TYPE_BACKUP_WAIT && operationType != OP_TYPE_RESTORE_WAIT) {
- Slog.wtf(TAG, "prepareOperationTimeout() doesn't support operation " +
- Integer.toHexString(token) + " of type " + operationType);
- return;
- }
- if (MORE_DEBUG) Slog.v(TAG, "starting timeout: token=" + Integer.toHexString(token)
- + " interval=" + interval + " callback=" + callback);
-
- synchronized (mCurrentOpLock) {
- mCurrentOperations.put(token, new Operation(OP_PENDING, callback, operationType));
- Message msg = mBackupHandler.obtainMessage(getMessageIdForOperationType(operationType),
- token, 0, callback);
- mBackupHandler.sendMessageDelayed(msg, interval);
- }
- }
-
- private int getMessageIdForOperationType(int operationType) {
- switch (operationType) {
- case OP_TYPE_BACKUP_WAIT:
- return MSG_BACKUP_OPERATION_TIMEOUT;
- case OP_TYPE_RESTORE_WAIT:
- return MSG_RESTORE_OPERATION_TIMEOUT;
- default:
- Slog.wtf(TAG, "getMessageIdForOperationType called on invalid operation type: " +
- operationType);
- return -1;
- }
- }
-
- private void removeOperation(int token) {
- if (MORE_DEBUG) {
- Slog.d(TAG, "Removing operation token=" + Integer.toHexString(token));
- }
- synchronized (mCurrentOpLock) {
- if (mCurrentOperations.get(token) == null) {
- Slog.w(TAG, "Duplicate remove for operation. token=" +
- Integer.toHexString(token));
- }
- mCurrentOperations.remove(token);
- }
- }
-
- // synchronous waiter case
- @Override
- public boolean waitUntilOperationComplete(int token) {
- if (MORE_DEBUG) Slog.i(TAG, "Blocking until operation complete for "
- + Integer.toHexString(token));
- int finalState = OP_PENDING;
- Operation op = null;
- synchronized (mCurrentOpLock) {
- while (true) {
- op = mCurrentOperations.get(token);
- if (op == null) {
- // mysterious disappearance: treat as success with no callback
- break;
- } else {
- if (op.state == OP_PENDING) {
- try {
- mCurrentOpLock.wait();
- } catch (InterruptedException e) {
- }
- // When the wait is notified we loop around and recheck the current state
- } else {
- if (MORE_DEBUG) {
- Slog.d(TAG, "Unblocked waiting for operation token=" +
- Integer.toHexString(token));
- }
- // No longer pending; we're done
- finalState = op.state;
- break;
- }
- }
- }
- }
-
- removeOperation(token);
- if (op != null) {
- mBackupHandler.removeMessages(getMessageIdForOperationType(op.type));
- }
- if (MORE_DEBUG) Slog.v(TAG, "operation " + Integer.toHexString(token)
- + " complete: finalState=" + finalState);
- return finalState == OP_ACKNOWLEDGED;
- }
-
- void handleCancel(int token, boolean cancelAll) {
- // Notify any synchronous waiters
- Operation op = null;
- synchronized (mCurrentOpLock) {
- op = mCurrentOperations.get(token);
- if (MORE_DEBUG) {
- if (op == null) Slog.w(TAG, "Cancel of token " + Integer.toHexString(token)
- + " but no op found");
- }
- int state = (op != null) ? op.state : OP_TIMEOUT;
- if (state == OP_ACKNOWLEDGED) {
- // The operation finished cleanly, so we have nothing more to do.
- if (DEBUG) {
- Slog.w(TAG, "Operation already got an ack." +
- "Should have been removed from mCurrentOperations.");
- }
- op = null;
- mCurrentOperations.delete(token);
- } else if (state == OP_PENDING) {
- if (DEBUG) Slog.v(TAG, "Cancel: token=" + Integer.toHexString(token));
- op.state = OP_TIMEOUT;
- // Can't delete op from mCurrentOperations here. waitUntilOperationComplete may be
- // called after we receive cancel here. We need this op's state there.
-
- // Remove all pending timeout messages of types OP_TYPE_BACKUP_WAIT and
- // OP_TYPE_RESTORE_WAIT. On the other hand, OP_TYPE_BACKUP cannot time out and
- // doesn't require cancellation.
- if (op.type == OP_TYPE_BACKUP_WAIT || op.type == OP_TYPE_RESTORE_WAIT) {
- mBackupHandler.removeMessages(getMessageIdForOperationType(op.type));
- }
- }
- mCurrentOpLock.notifyAll();
- }
-
- // If there's a TimeoutHandler for this event, call it
- if (op != null && op.callback != null) {
- if (MORE_DEBUG) {
- Slog.v(TAG, " Invoking cancel on " + op.callback);
- }
- op.callback.handleCancel(cancelAll);
- }
- }
-
- // ----- Back up a set of applications via a worker thread -----
-
- enum BackupState {
- INITIAL,
- RUNNING_QUEUE,
- FINAL
- }
-
- /**
- * This class handles the process of backing up a given list of key/value backup packages.
- * Also takes in a list of pending dolly backups and kicks them off when key/value backups
- * are done.
- *
- * Flow:
- * If required, backup @pm@.
- * For each pending key/value backup package:
- * - Bind to agent.
- * - Call agent.doBackup()
- * - Wait either for cancel/timeout or operationComplete() callback from the agent.
- * Start task to perform dolly backups.
- *
- * There are three entry points into this class:
- * - execute() [Called from the handler thread]
- * - operationComplete(long result) [Called from the handler thread]
- * - handleCancel(boolean cancelAll) [Can be called from any thread]
- * These methods synchronize on mCancelLock.
- *
- * Interaction with mCurrentOperations:
- * - An entry for this task is put into mCurrentOperations for the entire lifetime of the
- * task. This is useful to cancel the task if required.
- * - An ephemeral entry is put into mCurrentOperations each time we are waiting on for
- * response from a backup agent. This is used to plumb timeouts and completion callbacks.
- */
- class PerformBackupTask implements BackupRestoreTask {
- private static final String TAG = "PerformBackupTask";
-
- private final Object mCancelLock = new Object();
-
- IBackupTransport mTransport;
- ArrayList<BackupRequest> mQueue;
- ArrayList<BackupRequest> mOriginalQueue;
- File mStateDir;
- File mJournal;
- BackupState mCurrentState;
- List<String> mPendingFullBackups;
- IBackupObserver mObserver;
- IBackupManagerMonitor mMonitor;
-
- private final PerformFullTransportBackupTask mFullBackupTask;
- private final int mCurrentOpToken;
- private volatile int mEphemeralOpToken;
-
- // carried information about the current in-flight operation
- IBackupAgent mAgentBinder;
- PackageInfo mCurrentPackage;
- File mSavedStateName;
- File mBackupDataName;
- File mNewStateName;
- ParcelFileDescriptor mSavedState;
- ParcelFileDescriptor mBackupData;
- ParcelFileDescriptor mNewState;
- int mStatus;
- boolean mFinished;
- final boolean mUserInitiated;
- final boolean mNonIncremental;
-
- private volatile boolean mCancelAll;
-
- public PerformBackupTask(IBackupTransport transport, String dirName,
- ArrayList<BackupRequest> queue, File journal, IBackupObserver observer,
- IBackupManagerMonitor monitor, List<String> pendingFullBackups,
- boolean userInitiated, boolean nonIncremental) {
- mTransport = transport;
- mOriginalQueue = queue;
- mQueue = new ArrayList<>();
- mJournal = journal;
- mObserver = observer;
- mMonitor = monitor;
- mPendingFullBackups = pendingFullBackups;
- mUserInitiated = userInitiated;
- mNonIncremental = nonIncremental;
-
- mStateDir = new File(mBaseStateDir, dirName);
- mCurrentOpToken = generateRandomIntegerToken();
-
- mFinished = false;
-
- synchronized (mCurrentOpLock) {
- if (isBackupOperationInProgress()) {
- if (DEBUG) {
- Slog.d(TAG, "Skipping backup since one is already in progress.");
- }
- mCancelAll = true;
- mFullBackupTask = null;
- mCurrentState = BackupState.FINAL;
- addBackupTrace("Skipped. Backup already in progress.");
- } else {
- mCurrentState = BackupState.INITIAL;
- CountDownLatch latch = new CountDownLatch(1);
- String[] fullBackups =
- mPendingFullBackups.toArray(new String[mPendingFullBackups.size()]);
- mFullBackupTask =
- new PerformFullTransportBackupTask(/*fullBackupRestoreObserver*/ null,
- fullBackups, /*updateSchedule*/ false, /*runningJob*/ null,
- latch,
- mObserver, mMonitor, mUserInitiated);
-
- registerTask();
- addBackupTrace("STATE => INITIAL");
- }
- }
- }
-
- /**
- * Put this task in the repository of running tasks.
- */
- private void registerTask() {
- synchronized (mCurrentOpLock) {
- mCurrentOperations.put(mCurrentOpToken, new Operation(OP_PENDING, this,
- OP_TYPE_BACKUP));
- }
- }
-
- /**
- * Remove this task from repository of running tasks.
- */
- private void unregisterTask() {
- removeOperation(mCurrentOpToken);
- }
-
- // Main entry point: perform one chunk of work, updating the state as appropriate
- // and reposting the next chunk to the primary backup handler thread.
- @Override
- @GuardedBy("mCancelLock")
- public void execute() {
- synchronized (mCancelLock) {
- switch (mCurrentState) {
- case INITIAL:
- beginBackup();
- break;
-
- case RUNNING_QUEUE:
- invokeNextAgent();
- break;
-
- case FINAL:
- if (!mFinished) {
- finalizeBackup();
- } else {
- Slog.e(TAG, "Duplicate finish of K/V pass");
- }
- break;
- }
- }
- }
-
- // We're starting a backup pass. Initialize the transport and send
- // the PM metadata blob if we haven't already.
- void beginBackup() {
- if (DEBUG_BACKUP_TRACE) {
- clearBackupTrace();
- StringBuilder b = new StringBuilder(256);
- b.append("beginBackup: [");
- for (BackupRequest req : mOriginalQueue) {
- b.append(' ');
- b.append(req.packageName);
- }
- b.append(" ]");
- addBackupTrace(b.toString());
- }
-
- mAgentBinder = null;
- mStatus = BackupTransport.TRANSPORT_OK;
-
- // Sanity check: if the queue is empty we have no work to do.
- if (mOriginalQueue.isEmpty() && mPendingFullBackups.isEmpty()) {
- Slog.w(TAG, "Backup begun with an empty queue - nothing to do.");
- addBackupTrace("queue empty at begin");
- sendBackupFinished(mObserver, BackupManager.SUCCESS);
- executeNextState(BackupState.FINAL);
- return;
- }
-
- // We need to retain the original queue contents in case of transport
- // failure, but we want a working copy that we can manipulate along
- // the way.
- mQueue = (ArrayList<BackupRequest>) mOriginalQueue.clone();
-
- // When the transport is forcing non-incremental key/value payloads, we send the
- // metadata only if it explicitly asks for it.
- boolean skipPm = mNonIncremental;
-
- // The app metadata pseudopackage might also be represented in the
- // backup queue if apps have been added/removed since the last time
- // we performed a backup. Drop it from the working queue now that
- // we're committed to evaluating it for backup regardless.
- for (int i = 0; i < mQueue.size(); i++) {
- if (PACKAGE_MANAGER_SENTINEL.equals(mQueue.get(i).packageName)) {
- if (MORE_DEBUG) {
- Slog.i(TAG, "Metadata in queue; eliding");
- }
- mQueue.remove(i);
- skipPm = false;
- break;
- }
- }
-
- if (DEBUG) Slog.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
-
- File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
- try {
- final String transportName = mTransport.transportDirName();
- EventLog.writeEvent(EventLogTags.BACKUP_START, transportName);
-
- // If we haven't stored package manager metadata yet, we must init the transport.
- if (mStatus == BackupTransport.TRANSPORT_OK && pmState.length() <= 0) {
- Slog.i(TAG, "Initializing (wiping) backup state and transport storage");
- addBackupTrace("initializing transport " + transportName);
- resetBackupState(mStateDir); // Just to make sure.
- mStatus = mTransport.initializeDevice();
-
- addBackupTrace("transport.initializeDevice() == " + mStatus);
- if (mStatus == BackupTransport.TRANSPORT_OK) {
- EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
- } else {
- EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
- Slog.e(TAG, "Transport error in initializeDevice()");
- }
- }
-
- if (skipPm) {
- Slog.d(TAG, "Skipping backup of package metadata.");
- executeNextState(BackupState.RUNNING_QUEUE);
- } else {
- // The package manager doesn't have a proper <application> etc, but since
- // it's running here in the system process we can just set up its agent
- // directly and use a synthetic BackupRequest. We always run this pass
- // because it's cheap and this way we guarantee that we don't get out of
- // step even if we're selecting among various transports at run time.
- if (mStatus == BackupTransport.TRANSPORT_OK) {
- PackageManagerBackupAgent pmAgent = makeMetadataAgent();
- mStatus = invokeAgentForBackup(PACKAGE_MANAGER_SENTINEL,
- IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport);
- addBackupTrace("PMBA invoke: " + mStatus);
-
- // Because the PMBA is a local instance, it has already executed its
- // backup callback and returned. Blow away the lingering (spurious)
- // pending timeout message for it.
- mBackupHandler.removeMessages(MSG_BACKUP_OPERATION_TIMEOUT);
- }
- }
-
- if (mStatus == BackupTransport.TRANSPORT_NOT_INITIALIZED) {
- // The backend reports that our dataset has been wiped. Note this in
- // the event log; the no-success code below will reset the backup
- // state as well.
- EventLog.writeEvent(EventLogTags.BACKUP_RESET, transportName);
- }
- } catch (Exception e) {
- Slog.e(TAG, "Error in backup thread", e);
- addBackupTrace("Exception in backup thread: " + e);
- mStatus = BackupTransport.TRANSPORT_ERROR;
- } finally {
- // If we've succeeded so far, invokeAgentForBackup() will have run the PM
- // metadata and its completion/timeout callback will continue the state
- // machine chain. If it failed that won't happen; we handle that now.
- addBackupTrace("exiting prelim: " + mStatus);
- if (mStatus != BackupTransport.TRANSPORT_OK) {
- // if things went wrong at this point, we need to
- // restage everything and try again later.
- resetBackupState(mStateDir); // Just to make sure.
- // In case of any other error, it's backup transport error.
- sendBackupFinished(mObserver, BackupManager.ERROR_TRANSPORT_ABORTED);
- executeNextState(BackupState.FINAL);
- }
- }
- }
-
- // Transport has been initialized and the PM metadata submitted successfully
- // if that was warranted. Now we process the single next thing in the queue.
- void invokeNextAgent() {
- mStatus = BackupTransport.TRANSPORT_OK;
- addBackupTrace("invoke q=" + mQueue.size());
-
- // Sanity check that we have work to do. If not, skip to the end where
- // we reestablish the wakelock invariants etc.
- if (mQueue.isEmpty()) {
- if (MORE_DEBUG) Slog.i(TAG, "queue now empty");
- executeNextState(BackupState.FINAL);
- return;
- }
-
- // pop the entry we're going to process on this step
- BackupRequest request = mQueue.get(0);
- mQueue.remove(0);
-
- Slog.d(TAG, "starting key/value backup of " + request);
- addBackupTrace("launch agent for " + request.packageName);
-
- // Verify that the requested app exists; it might be something that
- // requested a backup but was then uninstalled. The request was
- // journalled and rather than tamper with the journal it's safer
- // to sanity-check here. This also gives us the classname of the
- // package's backup agent.
- try {
- mCurrentPackage = mPackageManager.getPackageInfo(request.packageName,
- PackageManager.GET_SIGNATURES);
- if (!appIsEligibleForBackup(mCurrentPackage.applicationInfo, mPackageManager)) {
- // The manifest has changed but we had a stale backup request pending.
- // This won't happen again because the app won't be requesting further
- // backups.
- Slog.i(TAG, "Package " + request.packageName
- + " no longer supports backup; skipping");
- addBackupTrace("skipping - not eligible, completion is noop");
- // Shouldn't happen in case of requested backup, as pre-check was done in
- // #requestBackup(), except to app update done concurrently
- sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
- BackupManager.ERROR_BACKUP_NOT_ALLOWED);
- executeNextState(BackupState.RUNNING_QUEUE);
- return;
- }
-
- if (appGetsFullBackup(mCurrentPackage)) {
- // It's possible that this app *formerly* was enqueued for key/value backup,
- // but has since been updated and now only supports the full-data path.
- // Don't proceed with a key/value backup for it in this case.
- Slog.i(TAG, "Package " + request.packageName
- + " requests full-data rather than key/value; skipping");
- addBackupTrace("skipping - fullBackupOnly, completion is noop");
- // Shouldn't happen in case of requested backup, as pre-check was done in
- // #requestBackup()
- sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
- BackupManager.ERROR_BACKUP_NOT_ALLOWED);
- executeNextState(BackupState.RUNNING_QUEUE);
- return;
- }
-
- if (appIsStopped(mCurrentPackage.applicationInfo)) {
- // The app has been force-stopped or cleared or just installed,
- // and not yet launched out of that state, so just as it won't
- // receive broadcasts, we won't run it for backup.
- addBackupTrace("skipping - stopped");
- sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
- BackupManager.ERROR_BACKUP_NOT_ALLOWED);
- executeNextState(BackupState.RUNNING_QUEUE);
- return;
- }
-
- IBackupAgent agent = null;
- try {
- mWakelock.setWorkSource(new WorkSource(mCurrentPackage.applicationInfo.uid));
- agent = bindToAgentSynchronous(mCurrentPackage.applicationInfo,
- ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL);
- addBackupTrace("agent bound; a? = " + (agent != null));
- if (agent != null) {
- mAgentBinder = agent;
- mStatus = invokeAgentForBackup(request.packageName, agent, mTransport);
- // at this point we'll either get a completion callback from the
- // agent, or a timeout message on the main handler. either way, we're
- // done here as long as we're successful so far.
- } else {
- // Timeout waiting for the agent
- mStatus = BackupTransport.AGENT_ERROR;
- }
- } catch (SecurityException ex) {
- // Try for the next one.
- Slog.d(TAG, "error in bind/backup", ex);
- mStatus = BackupTransport.AGENT_ERROR;
- addBackupTrace("agent SE");
- }
- } catch (NameNotFoundException e) {
- Slog.d(TAG, "Package does not exist; skipping");
- addBackupTrace("no such package");
- mStatus = BackupTransport.AGENT_UNKNOWN;
- } finally {
- mWakelock.setWorkSource(null);
-
- // If there was an agent error, no timeout/completion handling will occur.
- // That means we need to direct to the next state ourselves.
- if (mStatus != BackupTransport.TRANSPORT_OK) {
- BackupState nextState = BackupState.RUNNING_QUEUE;
- mAgentBinder = null;
-
- // An agent-level failure means we reenqueue this one agent for
- // a later retry, but otherwise proceed normally.
- if (mStatus == BackupTransport.AGENT_ERROR) {
- if (MORE_DEBUG) Slog.i(TAG, "Agent failure for " + request.packageName
- + " - restaging");
- dataChangedImpl(request.packageName);
- mStatus = BackupTransport.TRANSPORT_OK;
- if (mQueue.isEmpty()) nextState = BackupState.FINAL;
- sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
- BackupManager.ERROR_AGENT_FAILURE);
- } else if (mStatus == BackupTransport.AGENT_UNKNOWN) {
- // Failed lookup of the app, so we couldn't bring up an agent, but
- // we're otherwise fine. Just drop it and go on to the next as usual.
- mStatus = BackupTransport.TRANSPORT_OK;
- sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
- BackupManager.ERROR_PACKAGE_NOT_FOUND);
- } else {
- // Transport-level failure means we reenqueue everything
- revertAndEndBackup();
- nextState = BackupState.FINAL;
- }
-
- executeNextState(nextState);
- } else {
- // success case
- addBackupTrace("expecting completion/timeout callback");
- }
- }
- }
-
- void finalizeBackup() {
- addBackupTrace("finishing");
-
- // Mark packages that we didn't backup (because backup was cancelled, etc.) as needing
- // backup.
- for (BackupRequest req : mQueue) {
- dataChangedImpl(req.packageName);
- }
-
- // Either backup was successful, in which case we of course do not need
- // this pass's journal any more; or it failed, in which case we just
- // re-enqueued all of these packages in the current active journal.
- // Either way, we no longer need this pass's journal.
- if (mJournal != null && !mJournal.delete()) {
- Slog.e(TAG, "Unable to remove backup journal file " + mJournal);
- }
-
- // If everything actually went through and this is the first time we've
- // done a backup, we can now record what the current backup dataset token
- // is.
- if ((mCurrentToken == 0) && (mStatus == BackupTransport.TRANSPORT_OK)) {
- addBackupTrace("success; recording token");
- try {
- mCurrentToken = mTransport.getCurrentRestoreSet();
- writeRestoreTokens();
- } catch (Exception e) {
- // nothing for it at this point, unfortunately, but this will be
- // recorded the next time we fully succeed.
- Slog.e(TAG, "Transport threw reporting restore set: " + e.getMessage());
- addBackupTrace("transport threw returning token");
- }
- }
-
- // Set up the next backup pass - at this point we can set mBackupRunning
- // to false to allow another pass to fire, because we're done with the
- // state machine sequence and the wakelock is refcounted.
- synchronized (mQueueLock) {
- mBackupRunning = false;
- if (mStatus == BackupTransport.TRANSPORT_NOT_INITIALIZED) {
- // Make sure we back up everything and perform the one-time init
- if (MORE_DEBUG) Slog.d(TAG, "Server requires init; rerunning");
- addBackupTrace("init required; rerunning");
- try {
- final String name = mTransportManager.getTransportName(mTransport);
- if (name != null) {
- mPendingInits.add(name);
- } else {
- if (DEBUG) {
- Slog.w(TAG, "Couldn't find name of transport " + mTransport
- + " for init");
- }
- }
- } catch (Exception e) {
- Slog.w(TAG, "Failed to query transport name for init: " + e.getMessage());
- // swallow it and proceed; we don't rely on this
- }
- clearMetadata();
- backupNow();
- }
- }
-
- clearBackupTrace();
-
- unregisterTask();
-
- if (!mCancelAll && mStatus == BackupTransport.TRANSPORT_OK &&
- mPendingFullBackups != null && !mPendingFullBackups.isEmpty()) {
- Slog.d(TAG, "Starting full backups for: " + mPendingFullBackups);
- // Acquiring wakelock for PerformFullTransportBackupTask before its start.
- mWakelock.acquire();
- (new Thread(mFullBackupTask, "full-transport-requested")).start();
- } else if (mCancelAll) {
- if (mFullBackupTask != null) {
- mFullBackupTask.unregisterTask();
- }
- sendBackupFinished(mObserver, BackupManager.ERROR_BACKUP_CANCELLED);
- } else {
- mFullBackupTask.unregisterTask();
- switch (mStatus) {
- case BackupTransport.TRANSPORT_OK:
- sendBackupFinished(mObserver, BackupManager.SUCCESS);
- break;
- case BackupTransport.TRANSPORT_NOT_INITIALIZED:
- sendBackupFinished(mObserver, BackupManager.ERROR_TRANSPORT_ABORTED);
- break;
- case BackupTransport.TRANSPORT_ERROR:
- default:
- sendBackupFinished(mObserver, BackupManager.ERROR_TRANSPORT_ABORTED);
- break;
- }
- }
- mFinished = true;
- Slog.i(BackupManagerService.TAG, "K/V backup pass finished.");
- // Only once we're entirely finished do we release the wakelock for k/v backup.
- mWakelock.release();
- }
-
- // Remove the PM metadata state. This will generate an init on the next pass.
- void clearMetadata() {
- final File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
- if (pmState.exists()) pmState.delete();
- }
-
- // Invoke an agent's doBackup() and start a timeout message spinning on the main
- // handler in case it doesn't get back to us.
- int invokeAgentForBackup(String packageName, IBackupAgent agent,
- IBackupTransport transport) {
- if (DEBUG) Slog.d(TAG, "invokeAgentForBackup on " + packageName);
- addBackupTrace("invoking " + packageName);
-
- File blankStateName = new File(mStateDir, "blank_state");
- mSavedStateName = new File(mStateDir, packageName);
- mBackupDataName = new File(mDataDir, packageName + ".data");
- mNewStateName = new File(mStateDir, packageName + ".new");
- if (MORE_DEBUG) Slog.d(TAG, "data file: " + mBackupDataName);
-
- mSavedState = null;
- mBackupData = null;
- mNewState = null;
-
- boolean callingAgent = false;
- mEphemeralOpToken = generateRandomIntegerToken();
- try {
- // Look up the package info & signatures. This is first so that if it
- // throws an exception, there's no file setup yet that would need to
- // be unraveled.
- if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
- // The metadata 'package' is synthetic; construct one and make
- // sure our global state is pointed at it
- mCurrentPackage = new PackageInfo();
- mCurrentPackage.packageName = packageName;
- }
-
- // In a full backup, we pass a null ParcelFileDescriptor as
- // the saved-state "file". For key/value backups we pass the old state if
- // an incremental backup is required, and a blank state otherwise.
- mSavedState = ParcelFileDescriptor.open(
- mNonIncremental ? blankStateName : mSavedStateName,
- ParcelFileDescriptor.MODE_READ_ONLY |
- ParcelFileDescriptor.MODE_CREATE); // Make an empty file if necessary
-
- mBackupData = ParcelFileDescriptor.open(mBackupDataName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE |
- ParcelFileDescriptor.MODE_TRUNCATE);
-
- if (!SELinux.restorecon(mBackupDataName)) {
- Slog.e(TAG, "SELinux restorecon failed on " + mBackupDataName);
- }
-
- mNewState = ParcelFileDescriptor.open(mNewStateName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE |
- ParcelFileDescriptor.MODE_TRUNCATE);
-
- final long quota = mTransport.getBackupQuota(packageName, false /* isFullBackup */);
- callingAgent = true;
-
- // Initiate the target's backup pass
- addBackupTrace("setting timeout");
- prepareOperationTimeout(mEphemeralOpToken, TIMEOUT_BACKUP_INTERVAL, this,
- OP_TYPE_BACKUP_WAIT);
- addBackupTrace("calling agent doBackup()");
-
- agent.doBackup(mSavedState, mBackupData, mNewState, quota, mEphemeralOpToken,
- mBackupManagerBinder);
- } catch (Exception e) {
- Slog.e(TAG, "Error invoking for backup on " + packageName + ". " + e);
- addBackupTrace("exception: " + e);
- EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName,
- e.toString());
- errorCleanup();
- return callingAgent ? BackupTransport.AGENT_ERROR
- : BackupTransport.TRANSPORT_ERROR;
- } finally {
- if (mNonIncremental) {
- blankStateName.delete();
- }
- }
-
- // At this point the agent is off and running. The next thing to happen will
- // either be a callback from the agent, at which point we'll process its data
- // for transport, or a timeout. Either way the next phase will happen in
- // response to the TimeoutHandler interface callbacks.
- addBackupTrace("invoke success");
- return BackupTransport.TRANSPORT_OK;
- }
-
- public void failAgent(IBackupAgent agent, String message) {
- try {
- agent.fail(message);
- } catch (Exception e) {
- Slog.w(TAG, "Error conveying failure to " + mCurrentPackage.packageName);
- }
- }
-
- // SHA-1 a byte array and return the result in hex
- private String SHA1Checksum(byte[] input) {
- final byte[] checksum;
- try {
- MessageDigest md = MessageDigest.getInstance("SHA-1");
- checksum = md.digest(input);
- } catch (NoSuchAlgorithmException e) {
- Slog.e(TAG, "Unable to use SHA-1!");
- return "00";
- }
-
- StringBuffer sb = new StringBuffer(checksum.length * 2);
- for (int i = 0; i < checksum.length; i++) {
- sb.append(Integer.toHexString(checksum[i]));
- }
- return sb.toString();
- }
-
- private void writeWidgetPayloadIfAppropriate(FileDescriptor fd, String pkgName)
- throws IOException {
- // TODO: http://b/22388012
- byte[] widgetState = AppWidgetBackupBridge.getWidgetState(pkgName,
- UserHandle.USER_SYSTEM);
- // has the widget state changed since last time?
- final File widgetFile = new File(mStateDir, pkgName + "_widget");
- final boolean priorStateExists = widgetFile.exists();
-
- if (MORE_DEBUG) {
- if (priorStateExists || widgetState != null) {
- Slog.i(TAG, "Checking widget update: state=" + (widgetState != null)
- + " prior=" + priorStateExists);
- }
- }
-
- if (!priorStateExists && widgetState == null) {
- // no prior state, no new state => nothing to do
- return;
- }
-
- // if the new state is not null, we might need to compare checksums to
- // determine whether to update the widget blob in the archive. If the
- // widget state *is* null, we know a priori at this point that we simply
- // need to commit a deletion for it.
- String newChecksum = null;
- if (widgetState != null) {
- newChecksum = SHA1Checksum(widgetState);
- if (priorStateExists) {
- final String priorChecksum;
- try (
- FileInputStream fin = new FileInputStream(widgetFile);
- DataInputStream in = new DataInputStream(fin)
- ) {
- priorChecksum = in.readUTF();
- }
- if (Objects.equals(newChecksum, priorChecksum)) {
- // Same checksum => no state change => don't rewrite the widget data
- return;
- }
- }
- } // else widget state *became* empty, so we need to commit a deletion
-
- BackupDataOutput out = new BackupDataOutput(fd);
- if (widgetState != null) {
- try (
- FileOutputStream fout = new FileOutputStream(widgetFile);
- DataOutputStream stateOut = new DataOutputStream(fout)
- ) {
- stateOut.writeUTF(newChecksum);
- }
-
- out.writeEntityHeader(KEY_WIDGET_STATE, widgetState.length);
- out.writeEntityData(widgetState, widgetState.length);
- } else {
- // Widget state for this app has been removed; commit a deletion
- out.writeEntityHeader(KEY_WIDGET_STATE, -1);
- widgetFile.delete();
- }
- }
-
- @Override
- @GuardedBy("mCancelLock")
- public void operationComplete(long unusedResult) {
- removeOperation(mEphemeralOpToken);
- synchronized (mCancelLock) {
- // The agent reported back to us!
- if (mFinished) {
- Slog.d(TAG, "operationComplete received after task finished.");
- return;
- }
-
- if (mBackupData == null) {
- // This callback was racing with our timeout, so we've cleaned up the
- // agent state already and are on to the next thing. We have nothing
- // further to do here: agent state having been cleared means that we've
- // initiated the appropriate next operation.
- final String pkg = (mCurrentPackage != null)
- ? mCurrentPackage.packageName : "[none]";
- if (MORE_DEBUG) {
- Slog.i(TAG, "Callback after agent teardown: " + pkg);
- }
- addBackupTrace("late opComplete; curPkg = " + pkg);
- return;
- }
-
- final String pkgName = mCurrentPackage.packageName;
- final long filepos = mBackupDataName.length();
- FileDescriptor fd = mBackupData.getFileDescriptor();
- try {
- // If it's a 3rd party app, see whether they wrote any protected keys
- // and complain mightily if they are attempting shenanigans.
- if (mCurrentPackage.applicationInfo != null &&
- (mCurrentPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
- == 0) {
- ParcelFileDescriptor readFd = ParcelFileDescriptor.open(mBackupDataName,
- ParcelFileDescriptor.MODE_READ_ONLY);
- BackupDataInput in = new BackupDataInput(readFd.getFileDescriptor());
- try {
- while (in.readNextHeader()) {
- final String key = in.getKey();
- if (key != null && key.charAt(0) >= 0xff00) {
- // Not okay: crash them and bail.
- failAgent(mAgentBinder, "Illegal backup key: " + key);
- addBackupTrace("illegal key " + key + " from " + pkgName);
- EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, pkgName,
- "bad key");
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_ILLEGAL_KEY,
- mCurrentPackage,
- BackupManagerMonitor
- .LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- putMonitoringExtra(null,
- BackupManagerMonitor.EXTRA_LOG_ILLEGAL_KEY,
- key));
- mBackupHandler.removeMessages(MSG_BACKUP_OPERATION_TIMEOUT);
- sendBackupOnPackageResult(mObserver, pkgName,
- BackupManager.ERROR_AGENT_FAILURE);
- errorCleanup();
- // agentErrorCleanup() implicitly executes next state properly
- return;
- }
- in.skipEntityData();
- }
- } finally {
- if (readFd != null) {
- readFd.close();
- }
- }
- }
-
- // Piggyback the widget state payload, if any
- writeWidgetPayloadIfAppropriate(fd, pkgName);
- } catch (IOException e) {
- // Hard disk error; recovery/failure policy TBD. For now roll back,
- // but we may want to consider this a transport-level failure (i.e.
- // we're in such a bad state that we can't contemplate doing backup
- // operations any more during this pass).
- Slog.w(TAG, "Unable to save widget state for " + pkgName);
- try {
- Os.ftruncate(fd, filepos);
- } catch (ErrnoException ee) {
- Slog.w(TAG, "Unable to roll back!");
- }
- }
-
- // Spin the data off to the transport and proceed with the next stage.
- if (MORE_DEBUG) Slog.v(TAG, "operationComplete(): sending data to transport for "
- + pkgName);
- mBackupHandler.removeMessages(MSG_BACKUP_OPERATION_TIMEOUT);
- clearAgentState();
- addBackupTrace("operation complete");
-
- ParcelFileDescriptor backupData = null;
- mStatus = BackupTransport.TRANSPORT_OK;
- long size = 0;
- try {
- size = mBackupDataName.length();
- if (size > 0) {
- if (mStatus == BackupTransport.TRANSPORT_OK) {
- backupData = ParcelFileDescriptor.open(mBackupDataName,
- ParcelFileDescriptor.MODE_READ_ONLY);
- addBackupTrace("sending data to transport");
- int flags = mUserInitiated ? BackupTransport.FLAG_USER_INITIATED : 0;
- mStatus = mTransport.performBackup(mCurrentPackage, backupData, flags);
- }
-
- // TODO - We call finishBackup() for each application backed up, because
- // we need to know now whether it succeeded or failed. Instead, we should
- // hold off on finishBackup() until the end, which implies holding off on
- // renaming *all* the output state files (see below) until that happens.
-
- addBackupTrace("data delivered: " + mStatus);
- if (mStatus == BackupTransport.TRANSPORT_OK) {
- addBackupTrace("finishing op on transport");
- mStatus = mTransport.finishBackup();
- addBackupTrace("finished: " + mStatus);
- } else if (mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
- addBackupTrace("transport rejected package");
- }
- } else {
- if (MORE_DEBUG) Slog.i(TAG,
- "no backup data written; not calling transport");
- addBackupTrace("no data to send");
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_NO_DATA_TO_SEND,
- mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- null);
- }
-
- if (mStatus == BackupTransport.TRANSPORT_OK) {
- // After successful transport, delete the now-stale data
- // and juggle the files so that next time we supply the agent
- // with the new state file it just created.
- mBackupDataName.delete();
- mNewStateName.renameTo(mSavedStateName);
- sendBackupOnPackageResult(mObserver, pkgName, BackupManager.SUCCESS);
- EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE, pkgName, size);
- logBackupComplete(pkgName);
- } else if (mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
- // The transport has rejected backup of this specific package. Roll it
- // back but proceed with running the rest of the queue.
- mBackupDataName.delete();
- mNewStateName.delete();
- sendBackupOnPackageResult(mObserver, pkgName,
- BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
- EventLogTags.writeBackupAgentFailure(pkgName, "Transport rejected");
- } else if (mStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
- sendBackupOnPackageResult(mObserver, pkgName,
- BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
- EventLog.writeEvent(EventLogTags.BACKUP_QUOTA_EXCEEDED, pkgName);
- } else {
- // Actual transport-level failure to communicate the data to the backend
- sendBackupOnPackageResult(mObserver, pkgName,
- BackupManager.ERROR_TRANSPORT_ABORTED);
- EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName);
- }
- } catch (Exception e) {
- sendBackupOnPackageResult(mObserver, pkgName,
- BackupManager.ERROR_TRANSPORT_ABORTED);
- Slog.e(TAG, "Transport error backing up " + pkgName, e);
- EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName);
- mStatus = BackupTransport.TRANSPORT_ERROR;
- } finally {
- try {
- if (backupData != null) backupData.close();
- } catch (IOException e) {
- }
- }
-
- final BackupState nextState;
- if (mStatus == BackupTransport.TRANSPORT_OK
- || mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
- // Success or single-package rejection. Proceed with the next app if any,
- // otherwise we're done.
- nextState = (mQueue.isEmpty()) ? BackupState.FINAL : BackupState.RUNNING_QUEUE;
- } else if (mStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
- if (MORE_DEBUG) {
- Slog.d(TAG, "Package " + mCurrentPackage.packageName +
- " hit quota limit on k/v backup");
- }
- if (mAgentBinder != null) {
- try {
- long quota = mTransport.getBackupQuota(mCurrentPackage.packageName,
- false);
- mAgentBinder.doQuotaExceeded(size, quota);
- } catch (Exception e) {
- Slog.e(TAG, "Unable to notify about quota exceeded: " + e.getMessage());
- }
- }
- nextState = (mQueue.isEmpty()) ? BackupState.FINAL : BackupState.RUNNING_QUEUE;
- } else {
- // Any other error here indicates a transport-level failure. That means
- // we need to halt everything and reschedule everything for next time.
- revertAndEndBackup();
- nextState = BackupState.FINAL;
- }
-
- executeNextState(nextState);
- }
- }
-
-
- @Override
- @GuardedBy("mCancelLock")
- public void handleCancel(boolean cancelAll) {
- removeOperation(mEphemeralOpToken);
- synchronized (mCancelLock) {
- if (mFinished) {
- // We have already cancelled this operation.
- if (MORE_DEBUG) {
- Slog.d(TAG, "Ignoring stale cancel. cancelAll=" + cancelAll);
- }
- return;
- }
- mCancelAll = cancelAll;
- final String logPackageName = (mCurrentPackage != null)
- ? mCurrentPackage.packageName
- : "no_package_yet";
- Slog.i(TAG, "Cancel backing up " + logPackageName);
- EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, logPackageName);
- addBackupTrace("cancel of " + logPackageName + ", cancelAll=" + cancelAll);
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL,
- mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT,
- putMonitoringExtra(null, BackupManagerMonitor.EXTRA_LOG_CANCEL_ALL,
- mCancelAll));
- errorCleanup();
- if (!cancelAll) {
- // The current agent either timed out or was cancelled running doBackup().
- // Restage it for the next time we run a backup pass.
- // !!! TODO: keep track of failure counts per agent, and blacklist those which
- // fail repeatedly (i.e. have proved themselves to be buggy).
- executeNextState(
- mQueue.isEmpty() ? BackupState.FINAL : BackupState.RUNNING_QUEUE);
- dataChangedImpl(mCurrentPackage.packageName);
- } else {
- finalizeBackup();
- }
- }
- }
-
- void revertAndEndBackup() {
- if (MORE_DEBUG) Slog.i(TAG, "Reverting backup queue - restaging everything");
- addBackupTrace("transport error; reverting");
-
- // We want to reset the backup schedule based on whatever the transport suggests
- // by way of retry/backoff time.
- long delay;
- try {
- delay = mTransport.requestBackupTime();
- } catch (Exception e) {
- Slog.w(TAG, "Unable to contact transport for recommended backoff: " + e.getMessage());
- delay = 0; // use the scheduler's default
- }
- KeyValueBackupJob.schedule(mContext, delay, mConstants);
-
- for (BackupRequest request : mOriginalQueue) {
- dataChangedImpl(request.packageName);
- }
-
- }
-
- void errorCleanup() {
- mBackupDataName.delete();
- mNewStateName.delete();
- clearAgentState();
- }
-
- // Cleanup common to both success and failure cases
- void clearAgentState() {
- try { if (mSavedState != null) mSavedState.close(); } catch (IOException e) {}
- try { if (mBackupData != null) mBackupData.close(); } catch (IOException e) {}
- try { if (mNewState != null) mNewState.close(); } catch (IOException e) {}
- synchronized (mCurrentOpLock) {
- // Current-operation callback handling requires the validity of these various
- // bits of internal state as an invariant of the operation still being live.
- // This means we make sure to clear all of the state in unison inside the lock.
- mCurrentOperations.remove(mEphemeralOpToken);
- mSavedState = mBackupData = mNewState = null;
- }
-
- // If this was a pseudopackage there's no associated Activity Manager state
- if (mCurrentPackage.applicationInfo != null) {
- addBackupTrace("unbinding " + mCurrentPackage.packageName);
- try { // unbind even on timeout, just in case
- mActivityManager.unbindBackupAgent(mCurrentPackage.applicationInfo);
- } catch (RemoteException e) { /* can't happen; activity manager is local */ }
- }
- }
-
- void executeNextState(BackupState nextState) {
- if (MORE_DEBUG) Slog.i(TAG, " => executing next step on "
- + this + " nextState=" + nextState);
- addBackupTrace("executeNextState => " + nextState);
- mCurrentState = nextState;
- Message msg = mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, this);
- mBackupHandler.sendMessage(msg);
- }
- }
-
- private boolean isBackupOperationInProgress() {
- synchronized (mCurrentOpLock) {
- for (int i = 0; i < mCurrentOperations.size(); i++) {
- Operation op = mCurrentOperations.valueAt(i);
- if (op.type == OP_TYPE_BACKUP && op.state == OP_PENDING) {
- return true;
- }
- }
- }
- return false;
- }
-
-
- // ----- Full backup/restore to a file/socket -----
-
- class FullBackupObbConnection implements ServiceConnection {
- volatile IObbBackupService mService;
-
- FullBackupObbConnection() {
- mService = null;
- }
-
- public void establish() {
- if (MORE_DEBUG) Slog.i(TAG, "Initiating bind of OBB service on " + this);
- Intent obbIntent = new Intent().setComponent(new ComponentName(
- "com.android.sharedstoragebackup",
- "com.android.sharedstoragebackup.ObbBackupService"));
- BackupManagerService.this.mContext.bindServiceAsUser(
- obbIntent, this, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
- }
-
- public void tearDown() {
- BackupManagerService.this.mContext.unbindService(this);
- }
-
- public boolean backupObbs(PackageInfo pkg, OutputStream out) {
- boolean success = false;
- waitForConnection();
-
- ParcelFileDescriptor[] pipes = null;
- try {
- pipes = ParcelFileDescriptor.createPipe();
- int token = generateRandomIntegerToken();
- prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL,
- null, OP_TYPE_BACKUP_WAIT);
- mService.backupObbs(pkg.packageName, pipes[1], token, mBackupManagerBinder);
- routeSocketDataToOutput(pipes[0], out);
- success = waitUntilOperationComplete(token);
- } catch (Exception e) {
- Slog.w(TAG, "Unable to back up OBBs for " + pkg, e);
- } finally {
- try {
- out.flush();
- if (pipes != null) {
- if (pipes[0] != null) pipes[0].close();
- if (pipes[1] != null) pipes[1].close();
- }
- } catch (IOException e) {
- Slog.w(TAG, "I/O error closing down OBB backup", e);
- }
- }
- return success;
- }
-
- public void restoreObbFile(String pkgName, ParcelFileDescriptor data,
- long fileSize, int type, String path, long mode, long mtime,
- int token, IBackupManager callbackBinder) {
- waitForConnection();
-
- try {
- mService.restoreObbFile(pkgName, data, fileSize, type, path, mode, mtime,
- token, callbackBinder);
- } catch (Exception e) {
- Slog.w(TAG, "Unable to restore OBBs for " + pkgName, e);
- }
- }
-
- private void waitForConnection() {
- synchronized (this) {
- while (mService == null) {
- if (MORE_DEBUG) Slog.i(TAG, "...waiting for OBB service binding...");
- try {
- this.wait();
- } catch (InterruptedException e) { /* never interrupted */ }
- }
- if (MORE_DEBUG) Slog.i(TAG, "Connected to OBB service; continuing");
- }
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- synchronized (this) {
- mService = IObbBackupService.Stub.asInterface(service);
- if (MORE_DEBUG) Slog.i(TAG, "OBB service connection " + mService
- + " connected on " + this);
- this.notifyAll();
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- synchronized (this) {
- mService = null;
- if (MORE_DEBUG) Slog.i(TAG, "OBB service connection disconnected on " + this);
- this.notifyAll();
- }
- }
-
- }
-
- static void routeSocketDataToOutput(ParcelFileDescriptor inPipe, OutputStream out)
- throws IOException {
- // We do not take close() responsibility for the pipe FD
- FileInputStream raw = new FileInputStream(inPipe.getFileDescriptor());
- DataInputStream in = new DataInputStream(raw);
-
- byte[] buffer = new byte[32 * 1024];
- int chunkTotal;
- while ((chunkTotal = in.readInt()) > 0) {
- while (chunkTotal > 0) {
- int toRead = (chunkTotal > buffer.length) ? buffer.length : chunkTotal;
- int nRead = in.read(buffer, 0, toRead);
- out.write(buffer, 0, nRead);
- chunkTotal -= nRead;
- }
- }
- }
-
- @Override
- public void tearDownAgentAndKill(ApplicationInfo app) {
- if (app == null) {
- // Null means the system package, so just quietly move on. :)
- return;
- }
-
- try {
- // unbind and tidy up even on timeout or failure, just in case
- mActivityManager.unbindBackupAgent(app);
-
- // The agent was running with a stub Application object, so shut it down.
- // !!! We hardcode the confirmation UI's package name here rather than use a
- // manifest flag! TODO something less direct.
- if (app.uid >= Process.FIRST_APPLICATION_UID
- && !app.packageName.equals("com.android.backupconfirm")) {
- if (MORE_DEBUG) Slog.d(TAG, "Killing agent host process");
- mActivityManager.killApplicationProcess(app.processName, app.uid);
- } else {
- if (MORE_DEBUG) Slog.d(TAG, "Not killing after operation: " + app.processName);
- }
- } catch (RemoteException e) {
- Slog.d(TAG, "Lost app trying to shut down");
- }
- }
-
- // Core logic for performing one package's full backup, gathering the tarball from the
- // application and emitting it to the designated OutputStream.
-
- // Callout from the engine to an interested participant that might need to communicate
- // with the agent prior to asking it to move data
- interface FullBackupPreflight {
- /**
- * Perform the preflight operation necessary for the given package.
- * @param pkg The name of the package being proposed for full-data backup
- * @param agent Live BackupAgent binding to the target app's agent
- * @return BackupTransport.TRANSPORT_OK to proceed with the backup operation,
- * or one of the other BackupTransport.* error codes as appropriate
- */
- int preflightFullBackup(PackageInfo pkg, IBackupAgent agent);
-
- long getExpectedSizeOrErrorCode();
- };
-
- class FullBackupEngine {
- OutputStream mOutput;
- FullBackupPreflight mPreflightHook;
- BackupRestoreTask mTimeoutMonitor;
- IBackupAgent mAgent;
- File mFilesDir;
- File mManifestFile;
- File mMetadataFile;
- boolean mIncludeApks;
- PackageInfo mPkg;
- private final long mQuota;
- private final int mOpToken;
-
- class FullBackupRunner implements Runnable {
- PackageInfo mPackage;
- byte[] mWidgetData;
- IBackupAgent mAgent;
- ParcelFileDescriptor mPipe;
- int mToken;
- boolean mSendApk;
- boolean mWriteManifest;
-
- FullBackupRunner(PackageInfo pack, IBackupAgent agent, ParcelFileDescriptor pipe,
- int token, boolean sendApk, boolean writeManifest, byte[] widgetData)
- throws IOException {
- mPackage = pack;
- mWidgetData = widgetData;
- mAgent = agent;
- mPipe = ParcelFileDescriptor.dup(pipe.getFileDescriptor());
- mToken = token;
- mSendApk = sendApk;
- mWriteManifest = writeManifest;
- }
-
- @Override
- public void run() {
- try {
- FullBackupDataOutput output = new FullBackupDataOutput(mPipe);
-
- if (mWriteManifest) {
- final boolean writeWidgetData = mWidgetData != null;
- if (MORE_DEBUG) Slog.d(TAG, "Writing manifest for " + mPackage.packageName);
- writeAppManifest(mPackage, mPackageManager, mManifestFile, mSendApk, writeWidgetData);
- FullBackup.backupToTar(mPackage.packageName, null, null,
- mFilesDir.getAbsolutePath(),
- mManifestFile.getAbsolutePath(),
- output);
- mManifestFile.delete();
-
- // We only need to write a metadata file if we have widget data to stash
- if (writeWidgetData) {
- writeMetadata(mPackage, mMetadataFile, mWidgetData);
- FullBackup.backupToTar(mPackage.packageName, null, null,
- mFilesDir.getAbsolutePath(),
- mMetadataFile.getAbsolutePath(),
- output);
- mMetadataFile.delete();
- }
- }
-
- if (mSendApk) {
- writeApkToBackup(mPackage, output);
- }
-
- final boolean isSharedStorage =
- mPackage.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
- final long timeout = isSharedStorage ?
- TIMEOUT_SHARED_BACKUP_INTERVAL : TIMEOUT_FULL_BACKUP_INTERVAL;
-
- if (DEBUG) Slog.d(TAG, "Calling doFullBackup() on " + mPackage.packageName);
- prepareOperationTimeout(mToken, timeout, mTimeoutMonitor /* in parent class */,
- OP_TYPE_BACKUP_WAIT);
- mAgent.doFullBackup(mPipe, mQuota, mToken, mBackupManagerBinder);
- } catch (IOException e) {
- Slog.e(TAG, "Error running full backup for " + mPackage.packageName);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote agent vanished during full backup of "
- + mPackage.packageName);
- } finally {
- try {
- mPipe.close();
- } catch (IOException e) {}
- }
- }
- }
-
- FullBackupEngine(OutputStream output, FullBackupPreflight preflightHook, PackageInfo pkg,
- boolean alsoApks, BackupRestoreTask timeoutMonitor, long quota, int opToken) {
- mOutput = output;
- mPreflightHook = preflightHook;
- mPkg = pkg;
- mIncludeApks = alsoApks;
- mTimeoutMonitor = timeoutMonitor;
- mFilesDir = new File("/data/system");
- mManifestFile = new File(mFilesDir, BACKUP_MANIFEST_FILENAME);
- mMetadataFile = new File(mFilesDir, BACKUP_METADATA_FILENAME);
- mQuota = quota;
- mOpToken = opToken;
- }
-
- public int preflightCheck() throws RemoteException {
- if (mPreflightHook == null) {
- if (MORE_DEBUG) {
- Slog.v(TAG, "No preflight check");
- }
- return BackupTransport.TRANSPORT_OK;
- }
- if (initializeAgent()) {
- int result = mPreflightHook.preflightFullBackup(mPkg, mAgent);
- if (MORE_DEBUG) {
- Slog.v(TAG, "preflight returned " + result);
- }
- return result;
- } else {
- Slog.w(TAG, "Unable to bind to full agent for " + mPkg.packageName);
- return BackupTransport.AGENT_ERROR;
- }
- }
-
- public int backupOnePackage() throws RemoteException {
- int result = BackupTransport.AGENT_ERROR;
-
- if (initializeAgent()) {
- ParcelFileDescriptor[] pipes = null;
- try {
- pipes = ParcelFileDescriptor.createPipe();
-
- ApplicationInfo app = mPkg.applicationInfo;
- final boolean isSharedStorage =
- mPkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
- final boolean sendApk = mIncludeApks
- && !isSharedStorage
- && ((app.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) == 0)
- && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
- (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
-
- // TODO: http://b/22388012
- byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(mPkg.packageName,
- UserHandle.USER_SYSTEM);
-
- FullBackupRunner runner = new FullBackupRunner(mPkg, mAgent, pipes[1],
- mOpToken, sendApk, !isSharedStorage, widgetBlob);
- pipes[1].close(); // the runner has dup'd it
- pipes[1] = null;
- Thread t = new Thread(runner, "app-data-runner");
- t.start();
-
- // Now pull data from the app and stuff it into the output
- routeSocketDataToOutput(pipes[0], mOutput);
-
- if (!waitUntilOperationComplete(mOpToken)) {
- Slog.e(TAG, "Full backup failed on package " + mPkg.packageName);
- } else {
- if (MORE_DEBUG) {
- Slog.d(TAG, "Full package backup success: " + mPkg.packageName);
- }
- result = BackupTransport.TRANSPORT_OK;
- }
- } catch (IOException e) {
- Slog.e(TAG, "Error backing up " + mPkg.packageName + ": " + e.getMessage());
- result = BackupTransport.AGENT_ERROR;
- } finally {
- try {
- // flush after every package
- mOutput.flush();
- if (pipes != null) {
- if (pipes[0] != null) pipes[0].close();
- if (pipes[1] != null) pipes[1].close();
- }
- } catch (IOException e) {
- Slog.w(TAG, "Error bringing down backup stack");
- result = BackupTransport.TRANSPORT_ERROR;
- }
- }
- } else {
- Slog.w(TAG, "Unable to bind to full agent for " + mPkg.packageName);
- }
- tearDown();
- return result;
- }
-
- public void sendQuotaExceeded(final long backupDataBytes, final long quotaBytes) {
- if (initializeAgent()) {
- try {
- mAgent.doQuotaExceeded(backupDataBytes, quotaBytes);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception while telling agent about quota exceeded");
- }
- }
- }
-
- private boolean initializeAgent() {
- if (mAgent == null) {
- if (MORE_DEBUG) {
- Slog.d(TAG, "Binding to full backup agent : " + mPkg.packageName);
- }
- mAgent = bindToAgentSynchronous(mPkg.applicationInfo,
- ApplicationThreadConstants.BACKUP_MODE_FULL);
- }
- return mAgent != null;
- }
-
- private void writeApkToBackup(PackageInfo pkg, FullBackupDataOutput output) {
- // Forward-locked apps, system-bundled .apks, etc are filtered out before we get here
- // TODO: handle backing up split APKs
- final String appSourceDir = pkg.applicationInfo.getBaseCodePath();
- final String apkDir = new File(appSourceDir).getParent();
- FullBackup.backupToTar(pkg.packageName, FullBackup.APK_TREE_TOKEN, null,
- apkDir, appSourceDir, output);
-
- // TODO: migrate this to SharedStorageBackup, since AID_SYSTEM
- // doesn't have access to external storage.
-
- // Save associated .obb content if it exists and we did save the apk
- // check for .obb and save those too
- // TODO: http://b/22388012
- final UserEnvironment userEnv = new UserEnvironment(UserHandle.USER_SYSTEM);
- final File obbDir = userEnv.buildExternalStorageAppObbDirs(pkg.packageName)[0];
- if (obbDir != null) {
- if (MORE_DEBUG) Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath());
- File[] obbFiles = obbDir.listFiles();
- if (obbFiles != null) {
- final String obbDirName = obbDir.getAbsolutePath();
- for (File obb : obbFiles) {
- FullBackup.backupToTar(pkg.packageName, FullBackup.OBB_TREE_TOKEN, null,
- obbDirName, obb.getAbsolutePath(), output);
- }
- }
- }
- }
-
- // Widget metadata format. All header entries are strings ending in LF:
- //
- // Version 1 header:
- // BACKUP_METADATA_VERSION, currently "1"
- // package name
- //
- // File data (all integers are binary in network byte order)
- // *N: 4 : integer token identifying which metadata blob
- // 4 : integer size of this blob = N
- // N : raw bytes of this metadata blob
- //
- // Currently understood blobs (always in network byte order):
- //
- // widgets : metadata token = 0x01FFED01 (BACKUP_WIDGET_METADATA_TOKEN)
- //
- // Unrecognized blobs are *ignored*, not errors.
- private void writeMetadata(PackageInfo pkg, File destination, byte[] widgetData)
- throws IOException {
- StringBuilder b = new StringBuilder(512);
- StringBuilderPrinter printer = new StringBuilderPrinter(b);
- printer.println(Integer.toString(BACKUP_METADATA_VERSION));
- printer.println(pkg.packageName);
-
- FileOutputStream fout = new FileOutputStream(destination);
- BufferedOutputStream bout = new BufferedOutputStream(fout);
- DataOutputStream out = new DataOutputStream(bout);
- bout.write(b.toString().getBytes()); // bypassing DataOutputStream
-
- if (widgetData != null && widgetData.length > 0) {
- out.writeInt(BACKUP_WIDGET_METADATA_TOKEN);
- out.writeInt(widgetData.length);
- out.write(widgetData);
- }
- bout.flush();
- out.close();
-
- // As with the manifest file, guarantee idempotence of the archive metadata
- // for the widget block by using a fixed mtime on the transient file.
- destination.setLastModified(0);
- }
-
- private void tearDown() {
- if (mPkg != null) {
- tearDownAgentAndKill(mPkg.applicationInfo);
- }
- }
- }
-
- static void writeAppManifest(PackageInfo pkg, PackageManager packageManager, File manifestFile,
- boolean withApk, boolean withWidgets) throws IOException {
- // Manifest format. All data are strings ending in LF:
- // BACKUP_MANIFEST_VERSION, currently 1
- //
- // Version 1:
- // package name
- // package's versionCode
- // platform versionCode
- // getInstallerPackageName() for this package (maybe empty)
- // boolean: "1" if archive includes .apk; any other string means not
- // number of signatures == N
- // N*: signature byte array in ascii format per Signature.toCharsString()
- StringBuilder builder = new StringBuilder(4096);
- StringBuilderPrinter printer = new StringBuilderPrinter(builder);
-
- printer.println(Integer.toString(BACKUP_MANIFEST_VERSION));
- printer.println(pkg.packageName);
- printer.println(Integer.toString(pkg.versionCode));
- printer.println(Integer.toString(Build.VERSION.SDK_INT));
-
- String installerName = packageManager.getInstallerPackageName(pkg.packageName);
- printer.println((installerName != null) ? installerName : "");
-
- printer.println(withApk ? "1" : "0");
- if (pkg.signatures == null) {
- printer.println("0");
- } else {
- printer.println(Integer.toString(pkg.signatures.length));
- for (Signature sig : pkg.signatures) {
- printer.println(sig.toCharsString());
- }
- }
-
- FileOutputStream outstream = new FileOutputStream(manifestFile);
- outstream.write(builder.toString().getBytes());
- outstream.close();
-
- // We want the manifest block in the archive stream to be idempotent:
- // each time we generate a backup stream for the app, we want the manifest
- // block to be identical. The underlying tar mechanism sees it as a file,
- // though, and will propagate its mtime, causing the tar header to vary.
- // Avoid this problem by pinning the mtime to zero.
- manifestFile.setLastModified(0);
- }
-
- // Generic driver skeleton for full backup operations
- abstract class FullBackupTask implements Runnable {
- IFullBackupRestoreObserver mObserver;
-
- FullBackupTask(IFullBackupRestoreObserver observer) {
- mObserver = observer;
- }
-
- // wrappers for observer use
- final void sendStartBackup() {
- if (mObserver != null) {
- try {
- mObserver.onStartBackup();
- } catch (RemoteException e) {
- Slog.w(TAG, "full backup observer went away: startBackup");
- mObserver = null;
- }
- }
- }
-
- final void sendOnBackupPackage(String name) {
- if (mObserver != null) {
- try {
- // TODO: use a more user-friendly name string
- mObserver.onBackupPackage(name);
- } catch (RemoteException e) {
- Slog.w(TAG, "full backup observer went away: backupPackage");
- mObserver = null;
- }
- }
- }
-
- final void sendEndBackup() {
- if (mObserver != null) {
- try {
- mObserver.onEndBackup();
- } catch (RemoteException e) {
- Slog.w(TAG, "full backup observer went away: endBackup");
- mObserver = null;
- }
- }
- }
- }
-
- boolean deviceIsEncrypted() {
- try {
- return mStorageManager.getEncryptionState()
- != StorageManager.ENCRYPTION_STATE_NONE
- && mStorageManager.getPasswordType()
- != StorageManager.CRYPT_TYPE_DEFAULT;
- } catch (Exception e) {
- // If we can't talk to the storagemanager service we have a serious problem; fail
- // "secure" i.e. assuming that the device is encrypted.
- Slog.e(TAG, "Unable to communicate with storagemanager service: " + e.getMessage());
- return true;
- }
- }
-
- // Full backup task variant used for adb backup
- class PerformAdbBackupTask extends FullBackupTask implements BackupRestoreTask {
- FullBackupEngine mBackupEngine;
- final AtomicBoolean mLatch;
-
- ParcelFileDescriptor mOutputFile;
- DeflaterOutputStream mDeflater;
- boolean mIncludeApks;
- boolean mIncludeObbs;
- boolean mIncludeShared;
- boolean mDoWidgets;
- boolean mAllApps;
- boolean mIncludeSystem;
- boolean mCompress;
- boolean mKeyValue;
- ArrayList<String> mPackages;
- PackageInfo mCurrentTarget;
- String mCurrentPassword;
- String mEncryptPassword;
- private final int mCurrentOpToken;
-
- PerformAdbBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer,
- boolean includeApks, boolean includeObbs, boolean includeShared, boolean doWidgets,
- String curPassword, String encryptPassword, boolean doAllApps, boolean doSystem,
- boolean doCompress, boolean doKeyValue, String[] packages, AtomicBoolean latch) {
- super(observer);
- mCurrentOpToken = generateRandomIntegerToken();
- mLatch = latch;
-
- mOutputFile = fd;
- mIncludeApks = includeApks;
- mIncludeObbs = includeObbs;
- mIncludeShared = includeShared;
- mDoWidgets = doWidgets;
- mAllApps = doAllApps;
- mIncludeSystem = doSystem;
- mPackages = (packages == null)
- ? new ArrayList<String>()
- : new ArrayList<String>(Arrays.asList(packages));
- mCurrentPassword = curPassword;
- // when backing up, if there is a current backup password, we require that
- // the user use a nonempty encryption password as well. if one is supplied
- // in the UI we use that, but if the UI was left empty we fall back to the
- // current backup password (which was supplied by the user as well).
- if (encryptPassword == null || "".equals(encryptPassword)) {
- mEncryptPassword = curPassword;
- } else {
- mEncryptPassword = encryptPassword;
- }
- if (MORE_DEBUG) {
- Slog.w(TAG, "Encrypting backup with passphrase=" + mEncryptPassword);
- }
- mCompress = doCompress;
- mKeyValue = doKeyValue;
- }
-
- void addPackagesToSet(TreeMap<String, PackageInfo> set, List<String> pkgNames) {
- for (String pkgName : pkgNames) {
- if (!set.containsKey(pkgName)) {
- try {
- PackageInfo info = mPackageManager.getPackageInfo(pkgName,
- PackageManager.GET_SIGNATURES);
- set.put(pkgName, info);
- } catch (NameNotFoundException e) {
- Slog.w(TAG, "Unknown package " + pkgName + ", skipping");
- }
- }
- }
- }
-
- private OutputStream emitAesBackupHeader(StringBuilder headerbuf,
- OutputStream ofstream) throws Exception {
- // User key will be used to encrypt the master key.
- byte[] newUserSalt = randomBytes(PBKDF2_SALT_SIZE);
- SecretKey userKey = buildPasswordKey(PBKDF_CURRENT, mEncryptPassword, newUserSalt,
- PBKDF2_HASH_ROUNDS);
-
- // the master key is random for each backup
- byte[] masterPw = new byte[256 / 8];
- mRng.nextBytes(masterPw);
- byte[] checksumSalt = randomBytes(PBKDF2_SALT_SIZE);
-
- // primary encryption of the datastream with the random key
- Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
- SecretKeySpec masterKeySpec = new SecretKeySpec(masterPw, "AES");
- c.init(Cipher.ENCRYPT_MODE, masterKeySpec);
- OutputStream finalOutput = new CipherOutputStream(ofstream, c);
-
- // line 4: name of encryption algorithm
- headerbuf.append(ENCRYPTION_ALGORITHM_NAME);
- headerbuf.append('\n');
- // line 5: user password salt [hex]
- headerbuf.append(byteArrayToHex(newUserSalt));
- headerbuf.append('\n');
- // line 6: master key checksum salt [hex]
- headerbuf.append(byteArrayToHex(checksumSalt));
- headerbuf.append('\n');
- // line 7: number of PBKDF2 rounds used [decimal]
- headerbuf.append(PBKDF2_HASH_ROUNDS);
- headerbuf.append('\n');
-
- // line 8: IV of the user key [hex]
- Cipher mkC = Cipher.getInstance("AES/CBC/PKCS5Padding");
- mkC.init(Cipher.ENCRYPT_MODE, userKey);
-
- byte[] IV = mkC.getIV();
- headerbuf.append(byteArrayToHex(IV));
- headerbuf.append('\n');
-
- // line 9: master IV + key blob, encrypted by the user key [hex]. Blob format:
- // [byte] IV length = Niv
- // [array of Niv bytes] IV itself
- // [byte] master key length = Nmk
- // [array of Nmk bytes] master key itself
- // [byte] MK checksum hash length = Nck
- // [array of Nck bytes] master key checksum hash
- //
- // The checksum is the (master key + checksum salt), run through the
- // stated number of PBKDF2 rounds
- IV = c.getIV();
- byte[] mk = masterKeySpec.getEncoded();
- byte[] checksum = makeKeyChecksum(PBKDF_CURRENT, masterKeySpec.getEncoded(),
- checksumSalt, PBKDF2_HASH_ROUNDS);
-
- ByteArrayOutputStream blob = new ByteArrayOutputStream(IV.length + mk.length
- + checksum.length + 3);
- DataOutputStream mkOut = new DataOutputStream(blob);
- mkOut.writeByte(IV.length);
- mkOut.write(IV);
- mkOut.writeByte(mk.length);
- mkOut.write(mk);
- mkOut.writeByte(checksum.length);
- mkOut.write(checksum);
- mkOut.flush();
- byte[] encryptedMk = mkC.doFinal(blob.toByteArray());
- headerbuf.append(byteArrayToHex(encryptedMk));
- headerbuf.append('\n');
-
- return finalOutput;
- }
-
- private void finalizeBackup(OutputStream out) {
- try {
- // A standard 'tar' EOF sequence: two 512-byte blocks of all zeroes.
- byte[] eof = new byte[512 * 2]; // newly allocated == zero filled
- out.write(eof);
- } catch (IOException e) {
- Slog.w(TAG, "Error attempting to finalize backup stream");
- }
- }
-
- @Override
- public void run() {
- String includeKeyValue = mKeyValue ? ", including key-value backups" : "";
- Slog.i(TAG, "--- Performing adb backup" + includeKeyValue + " ---");
-
- TreeMap<String, PackageInfo> packagesToBackup = new TreeMap<String, PackageInfo>();
- FullBackupObbConnection obbConnection = new FullBackupObbConnection();
- obbConnection.establish(); // we'll want this later
-
- sendStartBackup();
-
- // doAllApps supersedes the package set if any
- if (mAllApps) {
- List<PackageInfo> allPackages = mPackageManager.getInstalledPackages(
- PackageManager.GET_SIGNATURES);
- for (int i = 0; i < allPackages.size(); i++) {
- PackageInfo pkg = allPackages.get(i);
- // Exclude system apps if we've been asked to do so
- if (mIncludeSystem == true
- || ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0)) {
- packagesToBackup.put(pkg.packageName, pkg);
- }
- }
- }
-
- // If we're doing widget state as well, ensure that we have all the involved
- // host & provider packages in the set
- if (mDoWidgets) {
- // TODO: http://b/22388012
- List<String> pkgs =
- AppWidgetBackupBridge.getWidgetParticipants(UserHandle.USER_SYSTEM);
- if (pkgs != null) {
- if (MORE_DEBUG) {
- Slog.i(TAG, "Adding widget participants to backup set:");
- StringBuilder sb = new StringBuilder(128);
- sb.append(" ");
- for (String s : pkgs) {
- sb.append(' ');
- sb.append(s);
- }
- Slog.i(TAG, sb.toString());
- }
- addPackagesToSet(packagesToBackup, pkgs);
- }
- }
-
- // Now process the command line argument packages, if any. Note that explicitly-
- // named system-partition packages will be included even if includeSystem was
- // set to false.
- if (mPackages != null) {
- addPackagesToSet(packagesToBackup, mPackages);
- }
-
- // Now we cull any inapplicable / inappropriate packages from the set. This
- // includes the special shared-storage agent package; we handle that one
- // explicitly at the end of the backup pass. Packages supporting key-value backup are
- // added to their own queue, and handled after packages supporting fullbackup.
- ArrayList<PackageInfo> keyValueBackupQueue = new ArrayList<>();
- Iterator<Entry<String, PackageInfo>> iter = packagesToBackup.entrySet().iterator();
- while (iter.hasNext()) {
- PackageInfo pkg = iter.next().getValue();
- if (!appIsEligibleForBackup(pkg.applicationInfo, mPackageManager)
- || appIsStopped(pkg.applicationInfo)) {
- iter.remove();
- if (DEBUG) {
- Slog.i(TAG, "Package " + pkg.packageName
- + " is not eligible for backup, removing.");
- }
- } else if (appIsKeyValueOnly(pkg)) {
- iter.remove();
- if (DEBUG) {
- Slog.i(TAG, "Package " + pkg.packageName
- + " is key-value.");
- }
- keyValueBackupQueue.add(pkg);
- }
- }
-
- // flatten the set of packages now so we can explicitly control the ordering
- ArrayList<PackageInfo> backupQueue =
- new ArrayList<PackageInfo>(packagesToBackup.values());
- FileOutputStream ofstream = new FileOutputStream(mOutputFile.getFileDescriptor());
- OutputStream out = null;
-
- PackageInfo pkg = null;
- try {
- boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0);
-
- // Only allow encrypted backups of encrypted devices
- if (deviceIsEncrypted() && !encrypting) {
- Slog.e(TAG, "Unencrypted backup of encrypted device; aborting");
- return;
- }
-
- OutputStream finalOutput = ofstream;
-
- // Verify that the given password matches the currently-active
- // backup password, if any
- if (!backupPasswordMatches(mCurrentPassword)) {
- if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
- return;
- }
-
- // Write the global file header. All strings are UTF-8 encoded; lines end
- // with a '\n' byte. Actual backup data begins immediately following the
- // final '\n'.
- //
- // line 1: "ANDROID BACKUP"
- // line 2: backup file format version, currently "5"
- // line 3: compressed? "0" if not compressed, "1" if compressed.
- // line 4: name of encryption algorithm [currently only "none" or "AES-256"]
- //
- // When line 4 is not "none", then additional header data follows:
- //
- // line 5: user password salt [hex]
- // line 6: master key checksum salt [hex]
- // line 7: number of PBKDF2 rounds to use (same for user & master) [decimal]
- // line 8: IV of the user key [hex]
- // line 9: master key blob [hex]
- // IV of the master key, master key itself, master key checksum hash
- //
- // The master key checksum is the master key plus its checksum salt, run through
- // 10k rounds of PBKDF2. This is used to verify that the user has supplied the
- // correct password for decrypting the archive: the master key decrypted from
- // the archive using the user-supplied password is also run through PBKDF2 in
- // this way, and if the result does not match the checksum as stored in the
- // archive, then we know that the user-supplied password does not match the
- // archive's.
- StringBuilder headerbuf = new StringBuilder(1024);
-
- headerbuf.append(BACKUP_FILE_HEADER_MAGIC);
- headerbuf.append(BACKUP_FILE_VERSION); // integer, no trailing \n
- headerbuf.append(mCompress ? "\n1\n" : "\n0\n");
-
- try {
- // Set up the encryption stage if appropriate, and emit the correct header
- if (encrypting) {
- finalOutput = emitAesBackupHeader(headerbuf, finalOutput);
- } else {
- headerbuf.append("none\n");
- }
-
- byte[] header = headerbuf.toString().getBytes("UTF-8");
- ofstream.write(header);
-
- // Set up the compression stage feeding into the encryption stage (if any)
- if (mCompress) {
- Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
- finalOutput = new DeflaterOutputStream(finalOutput, deflater, true);
- }
-
- out = finalOutput;
- } catch (Exception e) {
- // Should never happen!
- Slog.e(TAG, "Unable to emit archive header", e);
- return;
- }
-
- // Shared storage if requested
- if (mIncludeShared) {
- try {
- pkg = mPackageManager.getPackageInfo(SHARED_BACKUP_AGENT_PACKAGE, 0);
- backupQueue.add(pkg);
- } catch (NameNotFoundException e) {
- Slog.e(TAG, "Unable to find shared-storage backup handler");
- }
- }
-
- // Now actually run the constructed backup sequence for full backup
- int N = backupQueue.size();
- for (int i = 0; i < N; i++) {
- pkg = backupQueue.get(i);
- if (DEBUG) {
- Slog.i(TAG,"--- Performing full backup for package " + pkg.packageName
- + " ---");
- }
- final boolean isSharedStorage =
- pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
-
- mBackupEngine = new FullBackupEngine(out, null, pkg, mIncludeApks, this, Long.MAX_VALUE, mCurrentOpToken);
- sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
-
- // Don't need to check preflight result as there is no preflight hook.
- mCurrentTarget = pkg;
- mBackupEngine.backupOnePackage();
-
- // after the app's agent runs to handle its private filesystem
- // contents, back up any OBB content it has on its behalf.
- if (mIncludeObbs) {
- boolean obbOkay = obbConnection.backupObbs(pkg, out);
- if (!obbOkay) {
- throw new RuntimeException("Failure writing OBB stack for " + pkg);
- }
- }
- }
- // And for key-value backup if enabled
- if (mKeyValue) {
- for (PackageInfo keyValuePackage : keyValueBackupQueue) {
- if (DEBUG) {
- Slog.i(TAG, "--- Performing key-value backup for package "
- + keyValuePackage.packageName + " ---");
- }
- KeyValueAdbBackupEngine kvBackupEngine =
- new KeyValueAdbBackupEngine(out, keyValuePackage,
- BackupManagerService.this,
- mPackageManager, mBaseStateDir, mDataDir);
- sendOnBackupPackage(keyValuePackage.packageName);
- kvBackupEngine.backupOnePackage();
- }
- }
-
- // Done!
- finalizeBackup(out);
- } catch (RemoteException e) {
- Slog.e(TAG, "App died during full backup");
- } catch (Exception e) {
- Slog.e(TAG, "Internal exception during full backup", e);
- } finally {
- try {
- if (out != null) {
- out.flush();
- out.close();
- }
- mOutputFile.close();
- } catch (IOException e) {
- Slog.e(TAG, "IO error closing adb backup file: " + e.getMessage());
- }
- synchronized (mLatch) {
- mLatch.set(true);
- mLatch.notifyAll();
- }
- sendEndBackup();
- obbConnection.tearDown();
- if (DEBUG) Slog.d(TAG, "Full backup pass complete.");
- mWakelock.release();
- }
- }
-
- // BackupRestoreTask methods, used for timeout handling
- @Override
- public void execute() {
- // Unused
- }
-
- @Override
- public void operationComplete(long result) {
- // Unused
- }
-
- @Override
- public void handleCancel(boolean cancelAll) {
- final PackageInfo target = mCurrentTarget;
- if (DEBUG) {
- Slog.w(TAG, "adb backup cancel of " + target);
- }
- if (target != null) {
- tearDownAgentAndKill(mCurrentTarget.applicationInfo);
- }
- removeOperation(mCurrentOpToken);
- }
- }
-
- /**
- * Full backup task extension used for transport-oriented operation.
- *
- * Flow:
- * For each requested package:
- * - Spin off a new SinglePackageBackupRunner (mBackupRunner) for the current package.
- * - Wait until preflight is complete. (mBackupRunner.getPreflightResultBlocking())
- * - If preflight data size is within limit, start reading data from agent pipe and writing
- * to transport pipe. While there is data to send, call transport.sendBackupData(int) to
- * tell the transport how many bytes to expect on its pipe.
- * - After sending all data, call transport.finishBackup() if things went well. And
- * transport.cancelFullBackup() otherwise.
- *
- * Interactions with mCurrentOperations:
- * - An entry for this object is added to mCurrentOperations for the entire lifetime of this
- * object. Used to cancel the operation.
- * - SinglePackageBackupRunner and SinglePackageBackupPreflight will put ephemeral entries
- * to get timeouts or operation complete callbacks.
- *
- * Handling cancels:
- * - The contract we provide is that the task won't interact with the transport after
- * handleCancel() is done executing.
- * - This task blocks at 3 points: 1. Preflight result check 2. Reading on agent side pipe
- * and 3. Get backup result from mBackupRunner.
- * - Bubbling up handleCancel to mBackupRunner handles all 3: 1. Calls handleCancel on the
- * preflight operation which counts down on the preflight latch. 2. Tears down the agent,
- * so read() returns -1. 3. Notifies mCurrentOpLock which unblocks
- * mBackupRunner.getBackupResultBlocking().
- */
- class PerformFullTransportBackupTask extends FullBackupTask implements BackupRestoreTask {
- static final String TAG = "PFTBT";
-
- private final Object mCancelLock = new Object();
-
- ArrayList<PackageInfo> mPackages;
- PackageInfo mCurrentPackage;
- boolean mUpdateSchedule;
- CountDownLatch mLatch;
- FullBackupJob mJob; // if a scheduled job needs to be finished afterwards
- IBackupObserver mBackupObserver;
- IBackupManagerMonitor mMonitor;
- boolean mUserInitiated;
- private volatile IBackupTransport mTransport;
- SinglePackageBackupRunner mBackupRunner;
- private final int mBackupRunnerOpToken;
-
- // This is true when a backup operation for some package is in progress.
- private volatile boolean mIsDoingBackup;
- private volatile boolean mCancelAll;
- private final int mCurrentOpToken;
-
- PerformFullTransportBackupTask(IFullBackupRestoreObserver observer,
- String[] whichPackages, boolean updateSchedule,
- FullBackupJob runningJob, CountDownLatch latch, IBackupObserver backupObserver,
- IBackupManagerMonitor monitor, boolean userInitiated) {
- super(observer);
- mUpdateSchedule = updateSchedule;
- mLatch = latch;
- mJob = runningJob;
- mPackages = new ArrayList<PackageInfo>(whichPackages.length);
- mBackupObserver = backupObserver;
- mMonitor = monitor;
- mUserInitiated = userInitiated;
- mCurrentOpToken = generateRandomIntegerToken();
- mBackupRunnerOpToken = generateRandomIntegerToken();
-
- if (isBackupOperationInProgress()) {
- if (DEBUG) {
- Slog.d(TAG, "Skipping full backup. A backup is already in progress.");
- }
- mCancelAll = true;
- return;
- }
-
- registerTask();
-
- for (String pkg : whichPackages) {
- try {
- PackageInfo info = mPackageManager.getPackageInfo(pkg,
- PackageManager.GET_SIGNATURES);
- mCurrentPackage = info;
- if (!appIsEligibleForBackup(info.applicationInfo, mPackageManager)) {
- // Cull any packages that have indicated that backups are not permitted,
- // that run as system-domain uids but do not define their own backup agents,
- // as well as any explicit mention of the 'special' shared-storage agent
- // package (we handle that one at the end).
- if (MORE_DEBUG) {
- Slog.d(TAG, "Ignoring ineligible package " + pkg);
- }
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_INELIGIBLE,
- mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- null);
- sendBackupOnPackageResult(mBackupObserver, pkg,
- BackupManager.ERROR_BACKUP_NOT_ALLOWED);
- continue;
- } else if (!appGetsFullBackup(info)) {
- // Cull any packages that are found in the queue but now aren't supposed
- // to get full-data backup operations.
- if (MORE_DEBUG) {
- Slog.d(TAG, "Ignoring full-data backup of key/value participant "
- + pkg);
- }
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_KEY_VALUE_PARTICIPANT,
- mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- null);
- sendBackupOnPackageResult(mBackupObserver, pkg,
- BackupManager.ERROR_BACKUP_NOT_ALLOWED);
- continue;
- } else if (appIsStopped(info.applicationInfo)) {
- // Cull any packages in the 'stopped' state: they've either just been
- // installed or have explicitly been force-stopped by the user. In both
- // cases we do not want to launch them for backup.
- if (MORE_DEBUG) {
- Slog.d(TAG, "Ignoring stopped package " + pkg);
- }
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_STOPPED,
- mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- null);
- sendBackupOnPackageResult(mBackupObserver, pkg,
- BackupManager.ERROR_BACKUP_NOT_ALLOWED);
- continue;
- }
- mPackages.add(info);
- } catch (NameNotFoundException e) {
- Slog.i(TAG, "Requested package " + pkg + " not found; ignoring");
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_NOT_FOUND,
- mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- null);
- }
- }
- }
-
- private void registerTask() {
- synchronized (mCurrentOpLock) {
- Slog.d(TAG, "backupmanager pftbt token=" + Integer.toHexString(mCurrentOpToken));
- mCurrentOperations.put(mCurrentOpToken, new Operation(OP_PENDING, this,
- OP_TYPE_BACKUP));
- }
- }
-
- private void unregisterTask() {
- removeOperation(mCurrentOpToken);
- }
-
- @Override
- public void execute() {
- // Nothing to do.
- }
-
- @Override
- public void handleCancel(boolean cancelAll) {
- synchronized (mCancelLock) {
- // We only support 'cancelAll = true' case for this task. Cancelling of a single package
-
- // due to timeout is handled by SinglePackageBackupRunner and SinglePackageBackupPreflight.
-
- if (!cancelAll) {
- Slog.wtf(TAG, "Expected cancelAll to be true.");
- }
-
- if (mCancelAll) {
- Slog.d(TAG, "Ignoring duplicate cancel call.");
- return;
- }
-
- mCancelAll = true;
- if (mIsDoingBackup) {
- BackupManagerService.this.handleCancel(mBackupRunnerOpToken, cancelAll);
- try {
- mTransport.cancelFullBackup();
- } catch (RemoteException e) {
- Slog.w(TAG, "Error calling cancelFullBackup() on transport: " + e);
- // Can't do much.
- }
- }
- }
- }
-
- @Override
- public void operationComplete(long result) {
- // Nothing to do.
- }
-
- @Override
- public void run() {
-
- // data from the app, passed to us for bridging to the transport
- ParcelFileDescriptor[] enginePipes = null;
-
- // Pipe through which we write data to the transport
- ParcelFileDescriptor[] transportPipes = null;
-
- long backoff = 0;
- int backupRunStatus = BackupManager.SUCCESS;
-
- try {
- if (!mEnabled || !mProvisioned) {
- // Backups are globally disabled, so don't proceed.
- if (DEBUG) {
- Slog.i(TAG, "full backup requested but enabled=" + mEnabled
- + " provisioned=" + mProvisioned + "; ignoring");
- }
- int monitoringEvent;
- if (mProvisioned) {
- monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED;
- } else {
- monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED;
- }
- mMonitor = monitorEvent(mMonitor, monitoringEvent, null,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
- mUpdateSchedule = false;
- backupRunStatus = BackupManager.ERROR_BACKUP_NOT_ALLOWED;
- return;
- }
-
- mTransport = mTransportManager.getCurrentTransportBinder();
- if (mTransport == null) {
- Slog.w(TAG, "Transport not present; full data backup not performed");
- backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_TRANSPORT_NOT_PRESENT,
- mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
- null);
- return;
- }
-
- // Set up to send data to the transport
- final int N = mPackages.size();
- final byte[] buffer = new byte[8192];
- for (int i = 0; i < N; i++) {
- mBackupRunner = null;
- PackageInfo currentPackage = mPackages.get(i);
- String packageName = currentPackage.packageName;
- if (DEBUG) {
- Slog.i(TAG, "Initiating full-data transport backup of " + packageName
- + " token: " + mCurrentOpToken);
- }
- EventLog.writeEvent(EventLogTags.FULL_BACKUP_PACKAGE, packageName);
-
- transportPipes = ParcelFileDescriptor.createPipe();
-
- // Tell the transport the data's coming
- int flags = mUserInitiated ? BackupTransport.FLAG_USER_INITIATED : 0;
- int backupPackageStatus;
- long quota = Long.MAX_VALUE;
- synchronized (mCancelLock) {
- if (mCancelAll) {
- break;
- }
- backupPackageStatus = mTransport.performFullBackup(currentPackage,
- transportPipes[0], flags);
-
- if (backupPackageStatus == BackupTransport.TRANSPORT_OK) {
- quota = mTransport.getBackupQuota(currentPackage.packageName,
- true /* isFullBackup */);
- // Now set up the backup engine / data source end of things
- enginePipes = ParcelFileDescriptor.createPipe();
- mBackupRunner =
- new SinglePackageBackupRunner(enginePipes[1], currentPackage,
- mTransport, quota, mBackupRunnerOpToken);
- // The runner dup'd the pipe half, so we close it here
- enginePipes[1].close();
- enginePipes[1] = null;
-
- mIsDoingBackup = true;
- }
- }
- if (backupPackageStatus == BackupTransport.TRANSPORT_OK) {
-
- // The transport has its own copy of the read end of the pipe,
- // so close ours now
- transportPipes[0].close();
- transportPipes[0] = null;
-
- // Spin off the runner to fetch the app's data and pipe it
- // into the engine pipes
- (new Thread(mBackupRunner, "package-backup-bridge")).start();
-
- // Read data off the engine pipe and pass it to the transport
- // pipe until we hit EOD on the input stream. We do not take
- // close() responsibility for these FDs into these stream wrappers.
- FileInputStream in = new FileInputStream(
- enginePipes[0].getFileDescriptor());
- FileOutputStream out = new FileOutputStream(
- transportPipes[1].getFileDescriptor());
- long totalRead = 0;
- final long preflightResult = mBackupRunner.getPreflightResultBlocking();
- // Preflight result is negative if some error happened on preflight.
- if (preflightResult < 0) {
- if (MORE_DEBUG) {
- Slog.d(TAG, "Backup error after preflight of package "
- + packageName + ": " + preflightResult
- + ", not running backup.");
- }
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_ERROR_PREFLIGHT,
- mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- putMonitoringExtra(null,
- BackupManagerMonitor.EXTRA_LOG_PREFLIGHT_ERROR,
- preflightResult));
- backupPackageStatus = (int) preflightResult;
- } else {
- int nRead = 0;
- do {
- nRead = in.read(buffer);
- if (MORE_DEBUG) {
- Slog.v(TAG, "in.read(buffer) from app: " + nRead);
- }
- if (nRead > 0) {
- out.write(buffer, 0, nRead);
- synchronized (mCancelLock) {
- if (!mCancelAll) {
- backupPackageStatus = mTransport.sendBackupData(nRead);
- }
- }
- totalRead += nRead;
- if (mBackupObserver != null && preflightResult > 0) {
- sendBackupOnUpdate(mBackupObserver, packageName,
- new BackupProgress(preflightResult, totalRead));
- }
- }
- } while (nRead > 0
- && backupPackageStatus == BackupTransport.TRANSPORT_OK);
- // Despite preflight succeeded, package still can hit quota on flight.
- if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
- Slog.w(TAG, "Package hit quota limit in-flight " + packageName
- + ": " + totalRead + " of " + quota);
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_QUOTA_HIT_PREFLIGHT,
- mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
- null);
- mBackupRunner.sendQuotaExceeded(totalRead, quota);
- }
- }
-
- final int backupRunnerResult = mBackupRunner.getBackupResultBlocking();
-
- synchronized (mCancelLock) {
- mIsDoingBackup = false;
- // If mCancelCurrent is true, we have already called cancelFullBackup().
- if (!mCancelAll) {
- if (backupRunnerResult == BackupTransport.TRANSPORT_OK) {
- // If we were otherwise in a good state, now interpret the final
- // result based on what finishBackup() returns. If we're in a
- // failure case already, preserve that result and ignore whatever
- // finishBackup() reports.
- final int finishResult = mTransport.finishBackup();
- if (backupPackageStatus == BackupTransport.TRANSPORT_OK) {
- backupPackageStatus = finishResult;
- }
- } else {
- mTransport.cancelFullBackup();
- }
- }
- }
-
- // A transport-originated error here means that we've hit an error that the
- // runner doesn't know about, so it's still moving data but we're pulling the
- // rug out from under it. Don't ask for its result: we already know better
- // and we'll hang if we block waiting for it, since it relies on us to
- // read back the data it's writing into the engine. Just proceed with
- // a graceful failure. The runner/engine mechanism will tear itself
- // down cleanly when we close the pipes from this end. Transport-level
- // errors take precedence over agent/app-specific errors for purposes of
- // determining our course of action.
- if (backupPackageStatus == BackupTransport.TRANSPORT_OK) {
- // We still could fail in backup runner thread.
- if (backupRunnerResult != BackupTransport.TRANSPORT_OK) {
- // If there was an error in runner thread and
- // not TRANSPORT_ERROR here, overwrite it.
- backupPackageStatus = backupRunnerResult;
- }
- } else {
- if (MORE_DEBUG) {
- Slog.i(TAG, "Transport-level failure; cancelling agent work");
- }
- }
-
- if (MORE_DEBUG) {
- Slog.i(TAG, "Done delivering backup data: result="
- + backupPackageStatus);
- }
-
- if (backupPackageStatus != BackupTransport.TRANSPORT_OK) {
- Slog.e(TAG, "Error " + backupPackageStatus + " backing up "
- + packageName);
- }
-
- // Also ask the transport how long it wants us to wait before
- // moving on to the next package, if any.
- backoff = mTransport.requestFullBackupTime();
- if (DEBUG_SCHEDULING) {
- Slog.i(TAG, "Transport suggested backoff=" + backoff);
- }
-
- }
-
- // Roll this package to the end of the backup queue if we're
- // in a queue-driven mode (regardless of success/failure)
- if (mUpdateSchedule) {
- enqueueFullBackup(packageName, System.currentTimeMillis());
- }
-
- if (backupPackageStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
- sendBackupOnPackageResult(mBackupObserver, packageName,
- BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
- if (DEBUG) {
- Slog.i(TAG, "Transport rejected backup of " + packageName
- + ", skipping");
- }
- EventLog.writeEvent(EventLogTags.FULL_BACKUP_AGENT_FAILURE, packageName,
- "transport rejected");
- // This failure state can come either a-priori from the transport, or
- // from the preflight pass. If we got as far as preflight, we now need
- // to tear down the target process.
- if (mBackupRunner != null) {
- tearDownAgentAndKill(currentPackage.applicationInfo);
- }
- // ... and continue looping.
- } else if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
- sendBackupOnPackageResult(mBackupObserver, packageName,
- BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
- if (DEBUG) {
- Slog.i(TAG, "Transport quota exceeded for package: " + packageName);
- EventLog.writeEvent(EventLogTags.FULL_BACKUP_QUOTA_EXCEEDED,
- packageName);
- }
- tearDownAgentAndKill(currentPackage.applicationInfo);
- // Do nothing, clean up, and continue looping.
- } else if (backupPackageStatus == BackupTransport.AGENT_ERROR) {
- sendBackupOnPackageResult(mBackupObserver, packageName,
- BackupManager.ERROR_AGENT_FAILURE);
- Slog.w(TAG, "Application failure for package: " + packageName);
- EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName);
- tearDownAgentAndKill(currentPackage.applicationInfo);
- // Do nothing, clean up, and continue looping.
- } else if (backupPackageStatus == BackupManager.ERROR_BACKUP_CANCELLED) {
- sendBackupOnPackageResult(mBackupObserver, packageName,
- BackupManager.ERROR_BACKUP_CANCELLED);
- Slog.w(TAG, "Backup cancelled. package=" + packageName +
- ", cancelAll=" + mCancelAll);
- EventLog.writeEvent(EventLogTags.FULL_BACKUP_CANCELLED, packageName);
- tearDownAgentAndKill(currentPackage.applicationInfo);
- // Do nothing, clean up, and continue looping.
- } else if (backupPackageStatus != BackupTransport.TRANSPORT_OK) {
- sendBackupOnPackageResult(mBackupObserver, packageName,
- BackupManager.ERROR_TRANSPORT_ABORTED);
- Slog.w(TAG, "Transport failed; aborting backup: " + backupPackageStatus);
- EventLog.writeEvent(EventLogTags.FULL_BACKUP_TRANSPORT_FAILURE);
- // Abort entire backup pass.
- backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
- tearDownAgentAndKill(currentPackage.applicationInfo);
- return;
- } else {
- // Success!
- sendBackupOnPackageResult(mBackupObserver, packageName,
- BackupManager.SUCCESS);
- EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS, packageName);
- logBackupComplete(packageName);
- }
- cleanUpPipes(transportPipes);
- cleanUpPipes(enginePipes);
- if (currentPackage.applicationInfo != null) {
- Slog.i(TAG, "Unbinding agent in " + packageName);
- addBackupTrace("unbinding " + packageName);
- try {
- mActivityManager.unbindBackupAgent(currentPackage.applicationInfo);
- } catch (RemoteException e) { /* can't happen; activity manager is local */ }
- }
- }
- } catch (Exception e) {
- backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
- Slog.w(TAG, "Exception trying full transport backup", e);
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_EXCEPTION_FULL_BACKUP,
- mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- putMonitoringExtra(null,
- BackupManagerMonitor.EXTRA_LOG_EXCEPTION_FULL_BACKUP,
- Log.getStackTraceString(e)));
-
- } finally {
-
- if (mCancelAll) {
- backupRunStatus = BackupManager.ERROR_BACKUP_CANCELLED;
- }
-
- if (DEBUG) {
- Slog.i(TAG, "Full backup completed with status: " + backupRunStatus);
- }
- sendBackupFinished(mBackupObserver, backupRunStatus);
-
- cleanUpPipes(transportPipes);
- cleanUpPipes(enginePipes);
-
- unregisterTask();
-
- if (mJob != null) {
- mJob.finishBackupPass();
- }
-
- synchronized (mQueueLock) {
- mRunningFullBackupTask = null;
- }
-
- mLatch.countDown();
-
- // Now that we're actually done with schedule-driven work, reschedule
- // the next pass based on the new queue state.
- if (mUpdateSchedule) {
- scheduleNextFullBackupJob(backoff);
- }
-
- Slog.i(BackupManagerService.TAG, "Full data backup pass finished.");
- mWakelock.release();
- }
- }
-
- void cleanUpPipes(ParcelFileDescriptor[] pipes) {
- if (pipes != null) {
- if (pipes[0] != null) {
- ParcelFileDescriptor fd = pipes[0];
- pipes[0] = null;
- try {
- fd.close();
- } catch (IOException e) {
- Slog.w(TAG, "Unable to close pipe!");
- }
- }
- if (pipes[1] != null) {
- ParcelFileDescriptor fd = pipes[1];
- pipes[1] = null;
- try {
- fd.close();
- } catch (IOException e) {
- Slog.w(TAG, "Unable to close pipe!");
- }
- }
- }
- }
-
- // Run the backup and pipe it back to the given socket -- expects to run on
- // a standalone thread. The runner owns this half of the pipe, and closes
- // it to indicate EOD to the other end.
- class SinglePackageBackupPreflight implements BackupRestoreTask, FullBackupPreflight {
- final AtomicLong mResult = new AtomicLong(BackupTransport.AGENT_ERROR);
- final CountDownLatch mLatch = new CountDownLatch(1);
- final IBackupTransport mTransport;
- final long mQuota;
- private final int mCurrentOpToken;
-
- SinglePackageBackupPreflight(IBackupTransport transport, long quota, int currentOpToken) {
- mTransport = transport;
- mQuota = quota;
- mCurrentOpToken = currentOpToken;
- }
-
- @Override
- public int preflightFullBackup(PackageInfo pkg, IBackupAgent agent) {
- int result;
- try {
- prepareOperationTimeout(mCurrentOpToken, TIMEOUT_FULL_BACKUP_INTERVAL,
- this, OP_TYPE_BACKUP_WAIT);
- addBackupTrace("preflighting");
- if (MORE_DEBUG) {
- Slog.d(TAG, "Preflighting full payload of " + pkg.packageName);
- }
- agent.doMeasureFullBackup(mQuota, mCurrentOpToken, mBackupManagerBinder);
-
- // Now wait to get our result back. If this backstop timeout is reached without
- // the latch being thrown, flow will continue as though a result or "normal"
- // timeout had been produced. In case of a real backstop timeout, mResult
- // will still contain the value it was constructed with, AGENT_ERROR, which
- // intentionaly falls into the "just report failure" code.
- mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
-
- long totalSize = mResult.get();
- // If preflight timed out, mResult will contain error code as int.
- if (totalSize < 0) {
- return (int) totalSize;
- }
- if (MORE_DEBUG) {
- Slog.v(TAG, "Got preflight response; size=" + totalSize);
- }
-
- result = mTransport.checkFullBackupSize(totalSize);
- if (result == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
- if (MORE_DEBUG) {
- Slog.d(TAG, "Package hit quota limit on preflight " +
- pkg.packageName + ": " + totalSize + " of " + mQuota);
- }
- agent.doQuotaExceeded(totalSize, mQuota);
- }
- } catch (Exception e) {
- Slog.w(TAG, "Exception preflighting " + pkg.packageName + ": " + e.getMessage());
- result = BackupTransport.AGENT_ERROR;
- }
- return result;
- }
-
- @Override
- public void execute() {
- // Unused.
- }
-
- @Override
- public void operationComplete(long result) {
- // got the callback, and our preflightFullBackup() method is waiting for the result
- if (MORE_DEBUG) {
- Slog.i(TAG, "Preflight op complete, result=" + result);
- }
- mResult.set(result);
- mLatch.countDown();
- removeOperation(mCurrentOpToken);
- }
-
- @Override
- public void handleCancel(boolean cancelAll) {
- if (MORE_DEBUG) {
- Slog.i(TAG, "Preflight cancelled; failing");
- }
- mResult.set(BackupTransport.AGENT_ERROR);
- mLatch.countDown();
- removeOperation(mCurrentOpToken);
- }
-
- @Override
- public long getExpectedSizeOrErrorCode() {
- try {
- mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
- return mResult.get();
- } catch (InterruptedException e) {
- return BackupTransport.NO_MORE_DATA;
- }
- }
- }
-
- class SinglePackageBackupRunner implements Runnable, BackupRestoreTask {
- final ParcelFileDescriptor mOutput;
- final PackageInfo mTarget;
- final SinglePackageBackupPreflight mPreflight;
- final CountDownLatch mPreflightLatch;
- final CountDownLatch mBackupLatch;
- private final int mCurrentOpToken;
- private final int mEphemeralToken;
- private FullBackupEngine mEngine;
- private volatile int mPreflightResult;
- private volatile int mBackupResult;
- private final long mQuota;
- private volatile boolean mIsCancelled;
-
- SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target,
- IBackupTransport transport, long quota, int currentOpToken) throws IOException {
- mOutput = ParcelFileDescriptor.dup(output.getFileDescriptor());
- mTarget = target;
- mCurrentOpToken = currentOpToken;
- mEphemeralToken = generateRandomIntegerToken();
- mPreflight = new SinglePackageBackupPreflight(transport, quota, mEphemeralToken);
- mPreflightLatch = new CountDownLatch(1);
- mBackupLatch = new CountDownLatch(1);
- mPreflightResult = BackupTransport.AGENT_ERROR;
- mBackupResult = BackupTransport.AGENT_ERROR;
- mQuota = quota;
- registerTask();
- }
-
- void registerTask() {
- synchronized (mCurrentOpLock) {
- mCurrentOperations.put(mCurrentOpToken, new Operation(OP_PENDING, this,
- OP_TYPE_BACKUP_WAIT));
- }
- }
-
- void unregisterTask() {
- synchronized (mCurrentOpLock) {
- mCurrentOperations.remove(mCurrentOpToken);
- }
- }
-
- @Override
- public void run() {
- FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor());
- mEngine = new FullBackupEngine(out, mPreflight, mTarget, false, this, mQuota, mCurrentOpToken);
- try {
- try {
- if (!mIsCancelled) {
- mPreflightResult = mEngine.preflightCheck();
- }
- } finally {
- mPreflightLatch.countDown();
- }
- // If there is no error on preflight, continue backup.
- if (mPreflightResult == BackupTransport.TRANSPORT_OK) {
- if (!mIsCancelled) {
- mBackupResult = mEngine.backupOnePackage();
- }
- }
- } catch (Exception e) {
- Slog.e(TAG, "Exception during full package backup of " + mTarget.packageName);
- } finally {
- unregisterTask();
- mBackupLatch.countDown();
- try {
- mOutput.close();
- } catch (IOException e) {
- Slog.w(TAG, "Error closing transport pipe in runner");
- }
- }
- }
-
- public void sendQuotaExceeded(final long backupDataBytes, final long quotaBytes) {
- mEngine.sendQuotaExceeded(backupDataBytes, quotaBytes);
- }
-
- // If preflight succeeded, returns positive number - preflight size,
- // otherwise return negative error code.
- long getPreflightResultBlocking() {
- try {
- mPreflightLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
- if (mIsCancelled) {
- return BackupManager.ERROR_BACKUP_CANCELLED;
- }
- if (mPreflightResult == BackupTransport.TRANSPORT_OK) {
- return mPreflight.getExpectedSizeOrErrorCode();
- } else {
- return mPreflightResult;
- }
- } catch (InterruptedException e) {
- return BackupTransport.AGENT_ERROR;
- }
- }
-
- int getBackupResultBlocking() {
- try {
- mBackupLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
- if (mIsCancelled) {
- return BackupManager.ERROR_BACKUP_CANCELLED;
- }
- return mBackupResult;
- } catch (InterruptedException e) {
- return BackupTransport.AGENT_ERROR;
- }
- }
-
-
- // BackupRestoreTask interface: specifically, timeout detection
-
- @Override
- public void execute() { /* intentionally empty */ }
-
- @Override
- public void operationComplete(long result) { /* intentionally empty */ }
-
- @Override
- public void handleCancel(boolean cancelAll) {
- if (DEBUG) {
- Slog.w(TAG, "Full backup cancel of " + mTarget.packageName);
- }
-
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_FULL_BACKUP_CANCEL,
- mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null);
- mIsCancelled = true;
- // Cancel tasks spun off by this task.
- BackupManagerService.this.handleCancel(mEphemeralToken, cancelAll);
- tearDownAgentAndKill(mTarget.applicationInfo);
- // Free up everyone waiting on this task and its children.
- mPreflightLatch.countDown();
- mBackupLatch.countDown();
- // We are done with this operation.
- removeOperation(mCurrentOpToken);
- }
- }
- }
-
- // ----- Full-data backup scheduling -----
-
- /**
- * Schedule a job to tell us when it's a good time to run a full backup
- */
- void scheduleNextFullBackupJob(long transportMinLatency) {
- synchronized (mQueueLock) {
- if (mFullBackupQueue.size() > 0) {
- // schedule the next job at the point in the future when the least-recently
- // backed up app comes due for backup again; or immediately if it's already
- // due.
- final long upcomingLastBackup = mFullBackupQueue.get(0).lastBackup;
- final long timeSinceLast = System.currentTimeMillis() - upcomingLastBackup;
- final long interval = mConstants.getFullBackupIntervalMilliseconds();
- final long appLatency = (timeSinceLast < interval) ? (interval - timeSinceLast) : 0;
- final long latency = Math.max(transportMinLatency, appLatency);
- Runnable r = new Runnable() {
- @Override public void run() {
- FullBackupJob.schedule(mContext, latency, mConstants);
- }
- };
- mBackupHandler.postDelayed(r, 2500);
- } else {
- if (DEBUG_SCHEDULING) {
- Slog.i(TAG, "Full backup queue empty; not scheduling");
- }
- }
- }
- }
-
- /**
- * Remove a package from the full-data queue.
- */
- void dequeueFullBackupLocked(String packageName) {
- final int N = mFullBackupQueue.size();
- for (int i = N-1; i >= 0; i--) {
- final FullBackupEntry e = mFullBackupQueue.get(i);
- if (packageName.equals(e.packageName)) {
- mFullBackupQueue.remove(i);
- }
- }
- }
-
- /**
- * Enqueue full backup for the given app, with a note about when it last ran.
- */
- void enqueueFullBackup(String packageName, long lastBackedUp) {
- FullBackupEntry newEntry = new FullBackupEntry(packageName, lastBackedUp);
- synchronized (mQueueLock) {
- // First, sanity check that we aren't adding a duplicate. Slow but
- // straightforward; we'll have at most on the order of a few hundred
- // items in this list.
- dequeueFullBackupLocked(packageName);
-
- // This is also slow but easy for modest numbers of apps: work backwards
- // from the end of the queue until we find an item whose last backup
- // time was before this one, then insert this new entry after it. If we're
- // adding something new we don't bother scanning, and just prepend.
- int which = -1;
- if (lastBackedUp > 0) {
- for (which = mFullBackupQueue.size() - 1; which >= 0; which--) {
- final FullBackupEntry entry = mFullBackupQueue.get(which);
- if (entry.lastBackup <= lastBackedUp) {
- mFullBackupQueue.add(which + 1, newEntry);
- break;
- }
- }
- }
- if (which < 0) {
- // this one is earlier than any existing one, so prepend
- mFullBackupQueue.add(0, newEntry);
- }
- }
- writeFullBackupScheduleAsync();
- }
-
- private boolean fullBackupAllowable(IBackupTransport transport) {
- if (transport == null) {
- Slog.w(TAG, "Transport not present; full data backup not performed");
- return false;
- }
-
- // Don't proceed unless we have already established package metadata
- // for the current dataset via a key/value backup pass.
- try {
- File stateDir = new File(mBaseStateDir, transport.transportDirName());
- File pmState = new File(stateDir, PACKAGE_MANAGER_SENTINEL);
- if (pmState.length() <= 0) {
- if (DEBUG) {
- Slog.i(TAG, "Full backup requested but dataset not yet initialized");
- }
- return false;
- }
- } catch (Exception e) {
- Slog.w(TAG, "Unable to get transport name: " + e.getMessage());
- return false;
- }
-
- return true;
- }
-
- /**
- * Conditions are right for a full backup operation, so run one. 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.
- *
- * <p>This is the "start a full backup operation" entry point called by the scheduled job.
- *
- * @return Whether ongoing work will continue. The return value here will be passed
- * along as the return value to the scheduled job's onStartJob() callback.
- */
- @Override
- public boolean beginFullBackup(FullBackupJob scheduledJob) {
- final long now = System.currentTimeMillis();
- FullBackupEntry entry = null;
- final long fullBackupInterval;
- final long keyValueBackupInterval;
- synchronized (mConstants) {
- fullBackupInterval = mConstants.getFullBackupIntervalMilliseconds();
- keyValueBackupInterval = mConstants.getKeyValueBackupIntervalMilliseconds();
- }
- long latency = fullBackupInterval;
-
- if (!mEnabled || !mProvisioned) {
- // Backups are globally disabled, so don't proceed. We also don't reschedule
- // the job driving automatic backups; that job will be scheduled again when
- // the user enables backup.
- if (MORE_DEBUG) {
- Slog.i(TAG, "beginFullBackup but e=" + mEnabled
- + " p=" + mProvisioned + "; ignoring");
- }
- return false;
- }
-
- // Don't run the backup if we're in battery saver mode, but reschedule
- // to try again in the not-so-distant future.
- final PowerSaveState result =
- mPowerManager.getPowerSaveState(ServiceType.FULL_BACKUP);
- if (result.batterySaverEnabled) {
- if (DEBUG) Slog.i(TAG, "Deferring scheduled full backups in battery saver mode");
- FullBackupJob.schedule(mContext, keyValueBackupInterval, mConstants);
- return false;
- }
-
- if (DEBUG_SCHEDULING) {
- Slog.i(TAG, "Beginning scheduled full backup operation");
- }
-
- // Great; we're able to run full backup jobs now. See if we have any work to do.
- synchronized (mQueueLock) {
- if (mRunningFullBackupTask != null) {
- Slog.e(TAG, "Backup triggered but one already/still running!");
- return false;
- }
-
- // At this point we think that we have work to do, but possibly not right now.
- // Any exit without actually running backups will also require that we
- // reschedule the job.
- boolean runBackup = true;
- boolean headBusy;
-
- do {
- // Recheck each time, because culling due to ineligibility may
- // have emptied the queue.
- if (mFullBackupQueue.size() == 0) {
- // no work to do so just bow out
- if (DEBUG) {
- Slog.i(TAG, "Backup queue empty; doing nothing");
- }
- runBackup = false;
- break;
- }
-
- headBusy = false;
-
- if (!fullBackupAllowable(mTransportManager.getCurrentTransportBinder())) {
- if (MORE_DEBUG) {
- Slog.i(TAG, "Preconditions not met; not running full backup");
- }
- runBackup = false;
- // Typically this means we haven't run a key/value backup yet. Back off
- // full-backup operations by the key/value job's run interval so that
- // next time we run, we are likely to be able to make progress.
- latency = keyValueBackupInterval;
- }
-
- if (runBackup) {
- entry = mFullBackupQueue.get(0);
- long timeSinceRun = now - entry.lastBackup;
- runBackup = (timeSinceRun >= fullBackupInterval);
- if (!runBackup) {
- // It's too early to back up the next thing in the queue, so bow out
- if (MORE_DEBUG) {
- Slog.i(TAG, "Device ready but too early to back up next app");
- }
- // Wait until the next app in the queue falls due for a full data backup
- latency = fullBackupInterval - timeSinceRun;
- break; // we know we aren't doing work yet, so bail.
- }
-
- try {
- PackageInfo appInfo = mPackageManager.getPackageInfo(entry.packageName, 0);
- if (!appGetsFullBackup(appInfo)) {
- // The head app isn't supposed to get full-data backups [any more];
- // so we cull it and force a loop around to consider the new head
- // app.
- if (MORE_DEBUG) {
- Slog.i(TAG, "Culling package " + entry.packageName
- + " in full-backup queue but not eligible");
- }
- mFullBackupQueue.remove(0);
- headBusy = true; // force the while() condition
- continue;
- }
-
- final int privFlags = appInfo.applicationInfo.privateFlags;
- headBusy = (privFlags & PRIVATE_FLAG_BACKUP_IN_FOREGROUND) == 0
- && mActivityManager.isAppForeground(appInfo.applicationInfo.uid);
-
- if (headBusy) {
- final long nextEligible = System.currentTimeMillis()
- + BUSY_BACKOFF_MIN_MILLIS
- + mTokenGenerator.nextInt(BUSY_BACKOFF_FUZZ);
- if (DEBUG_SCHEDULING) {
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- Slog.i(TAG, "Full backup time but " + entry.packageName
- + " is busy; deferring to "
- + sdf.format(new Date(nextEligible)));
- }
- // This relocates the app's entry from the head of the queue to
- // its order-appropriate position further down, so upon looping
- // a new candidate will be considered at the head.
- enqueueFullBackup(entry.packageName, nextEligible - fullBackupInterval);
- }
- } catch (NameNotFoundException nnf) {
- // So, we think we want to back this up, but it turns out the package
- // in question is no longer installed. We want to drop it from the
- // queue entirely and move on, but if there's nothing else in the queue
- // we should bail entirely. headBusy cannot have been set to true yet.
- runBackup = (mFullBackupQueue.size() > 1);
- } catch (RemoteException e) {
- // Cannot happen; the Activity Manager is in the same process
- }
- }
- } while (headBusy);
-
- if (!runBackup) {
- if (DEBUG_SCHEDULING) {
- Slog.i(TAG, "Nothing pending full backup; rescheduling +" + latency);
- }
- final long deferTime = latency; // pin for the closure
- mBackupHandler.post(new Runnable() {
- @Override public void run() {
- FullBackupJob.schedule(mContext, deferTime, mConstants);
- }
- });
- return false;
- }
-
- // Okay, the top thing is ready for backup now. Do it.
- mFullBackupQueue.remove(0);
- CountDownLatch latch = new CountDownLatch(1);
- String[] pkg = new String[] {entry.packageName};
- mRunningFullBackupTask = new PerformFullTransportBackupTask(null, pkg, true,
- scheduledJob, latch, null, null, false /* userInitiated */);
- // Acquiring wakelock for PerformFullTransportBackupTask before its start.
- mWakelock.acquire();
- (new Thread(mRunningFullBackupTask)).start();
- }
-
- return true;
- }
-
- // The job scheduler says our constraints don't hold any more,
- // so tear down any ongoing backup task right away.
- @Override
- public void endFullBackup() {
- // offload the mRunningFullBackupTask.handleCancel() call to another thread,
- // as we might have to wait for mCancelLock
- Runnable endFullBackupRunnable = new Runnable() {
- @Override
- public void run() {
- PerformFullTransportBackupTask pftbt = null;
- synchronized (mQueueLock) {
- if (mRunningFullBackupTask != null) {
- pftbt = mRunningFullBackupTask;
- }
- }
- if (pftbt != null) {
- if (DEBUG_SCHEDULING) {
- Slog.i(TAG, "Telling running backup to stop");
- }
- pftbt.handleCancel(true);
- }
- }
- };
- new Thread(endFullBackupRunnable, "end-full-backup").start();
- }
-
- // ----- Restore infrastructure -----
-
- abstract class RestoreEngine {
- static final String TAG = "RestoreEngine";
-
- public static final int SUCCESS = 0;
- public static final int TARGET_FAILURE = -2;
- public static final int TRANSPORT_FAILURE = -3;
-
- private AtomicBoolean mRunning = new AtomicBoolean(false);
- private AtomicInteger mResult = new AtomicInteger(SUCCESS);
-
- public boolean isRunning() {
- return mRunning.get();
- }
-
- public void setRunning(boolean stillRunning) {
- synchronized (mRunning) {
- mRunning.set(stillRunning);
- mRunning.notifyAll();
- }
- }
-
- public int waitForResult() {
- synchronized (mRunning) {
- while (isRunning()) {
- try {
- mRunning.wait();
- } catch (InterruptedException e) {}
- }
- }
- return getResult();
- }
-
- public int getResult() {
- return mResult.get();
- }
-
- public void setResult(int result) {
- mResult.set(result);
- }
-
- // TODO: abstract restore state and APIs
- }
-
- // ----- Full restore from a file/socket -----
-
- enum RestorePolicy {
- IGNORE,
- ACCEPT,
- ACCEPT_IF_APK
- }
-
- // Full restore engine, used by both adb restore and transport-based full restore
- class FullRestoreEngine extends RestoreEngine {
- // Task in charge of monitoring timeouts
- BackupRestoreTask mMonitorTask;
-
- // Dedicated observer, if any
- IFullBackupRestoreObserver mObserver;
-
- IBackupManagerMonitor mMonitor;
-
- // Where we're delivering the file data as we go
- IBackupAgent mAgent;
-
- // Are we permitted to only deliver a specific package's metadata?
- PackageInfo mOnlyPackage;
-
- boolean mAllowApks;
- boolean mAllowObbs;
-
- // Which package are we currently handling data for?
- String mAgentPackage;
-
- // Info for working with the target app process
- ApplicationInfo mTargetApp;
-
- // Machinery for restoring OBBs
- FullBackupObbConnection mObbConnection = null;
-
- // possible handling states for a given package in the restore dataset
- final HashMap<String, RestorePolicy> mPackagePolicies
- = new HashMap<String, RestorePolicy>();
-
- // installer package names for each encountered app, derived from the manifests
- final HashMap<String, String> mPackageInstallers = new HashMap<String, String>();
-
- // Signatures for a given package found in its manifest file
- final HashMap<String, Signature[]> mManifestSignatures
- = new HashMap<String, Signature[]>();
-
- // Packages we've already wiped data on when restoring their first file
- final HashSet<String> mClearedPackages = new HashSet<String>();
-
- // How much data have we moved?
- long mBytes;
-
- // Working buffer
- byte[] mBuffer;
-
- // Pipes for moving data
- ParcelFileDescriptor[] mPipes = null;
-
- // Widget blob to be restored out-of-band
- byte[] mWidgetData = null;
-
- private final int mEphemeralOpToken;
-
- // Runner that can be placed in a separate thread to do in-process
- // invocations of the full restore API asynchronously. Used by adb restore.
- class RestoreFileRunnable implements Runnable {
- IBackupAgent mAgent;
- FileMetadata mInfo;
- ParcelFileDescriptor mSocket;
- int mToken;
-
- RestoreFileRunnable(IBackupAgent agent, FileMetadata info,
- ParcelFileDescriptor socket, int token) throws IOException {
- mAgent = agent;
- mInfo = info;
- mToken = token;
-
- // This class is used strictly for process-local binder invocations. The
- // semantics of ParcelFileDescriptor differ in this case; in particular, we
- // do not automatically get a 'dup'ed descriptor that we can can continue
- // to use asynchronously from the caller. So, we make sure to dup it ourselves
- // before proceeding to do the restore.
- mSocket = ParcelFileDescriptor.dup(socket.getFileDescriptor());
- }
-
- @Override
- public void run() {
- try {
- mAgent.doRestoreFile(mSocket, mInfo.size, mInfo.type,
- mInfo.domain, mInfo.path, mInfo.mode, mInfo.mtime,
- mToken, mBackupManagerBinder);
- } catch (RemoteException e) {
- // never happens; this is used strictly for local binder calls
- }
- }
- }
-
- public FullRestoreEngine(BackupRestoreTask monitorTask, IFullBackupRestoreObserver observer,
- IBackupManagerMonitor monitor, PackageInfo onlyPackage, boolean allowApks,
- boolean allowObbs, int ephemeralOpToken) {
- mEphemeralOpToken = ephemeralOpToken;
- mMonitorTask = monitorTask;
- mObserver = observer;
- mMonitor = monitor;
- mOnlyPackage = onlyPackage;
- mAllowApks = allowApks;
- mAllowObbs = allowObbs;
- mBuffer = new byte[32 * 1024];
- mBytes = 0;
- }
-
- public IBackupAgent getAgent() {
- return mAgent;
- }
-
- public byte[] getWidgetData() {
- return mWidgetData;
- }
-
- public boolean restoreOneFile(InputStream instream, boolean mustKillAgent) {
- if (!isRunning()) {
- Slog.w(TAG, "Restore engine used after halting");
- return false;
- }
-
- FileMetadata info;
- try {
- if (MORE_DEBUG) {
- Slog.v(TAG, "Reading tar header for restoring file");
- }
- info = readTarHeaders(instream);
- if (info != null) {
- if (MORE_DEBUG) {
- dumpFileMetadata(info);
- }
-
- final String pkg = info.packageName;
- if (!pkg.equals(mAgentPackage)) {
- // In the single-package case, it's a semantic error to expect
- // one app's data but see a different app's on the wire
- if (mOnlyPackage != null) {
- if (!pkg.equals(mOnlyPackage.packageName)) {
- Slog.w(TAG, "Expected data for " + mOnlyPackage
- + " but saw " + pkg);
- setResult(RestoreEngine.TRANSPORT_FAILURE);
- setRunning(false);
- return false;
- }
- }
-
- // okay, change in package; set up our various
- // bookkeeping if we haven't seen it yet
- if (!mPackagePolicies.containsKey(pkg)) {
- mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
- }
-
- // Clean up the previous agent relationship if necessary,
- // and let the observer know we're considering a new app.
- if (mAgent != null) {
- if (DEBUG) Slog.d(TAG, "Saw new package; finalizing old one");
- // Now we're really done
- tearDownPipes();
- tearDownAgent(mTargetApp);
- mTargetApp = null;
- mAgentPackage = null;
- }
- }
-
- if (info.path.equals(BACKUP_MANIFEST_FILENAME)) {
- mPackagePolicies.put(pkg, readAppManifest(info, instream));
- mPackageInstallers.put(pkg, info.installerPackageName);
- // We've read only the manifest content itself at this point,
- // so consume the footer before looping around to the next
- // input file
- skipTarPadding(info.size, instream);
- sendOnRestorePackage(pkg);
- } else if (info.path.equals(BACKUP_METADATA_FILENAME)) {
- // Metadata blobs!
- readMetadata(info, instream);
- skipTarPadding(info.size, instream);
- } else {
- // Non-manifest, so it's actual file data. Is this a package
- // we're ignoring?
- boolean okay = true;
- RestorePolicy policy = mPackagePolicies.get(pkg);
- switch (policy) {
- case IGNORE:
- okay = false;
- break;
-
- case ACCEPT_IF_APK:
- // If we're in accept-if-apk state, then the first file we
- // see MUST be the apk.
- if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
- if (DEBUG) Slog.d(TAG, "APK file; installing");
- // Try to install the app.
- String installerName = mPackageInstallers.get(pkg);
- okay = installApk(info, installerName, instream);
- // good to go; promote to ACCEPT
- mPackagePolicies.put(pkg, (okay)
- ? RestorePolicy.ACCEPT
- : RestorePolicy.IGNORE);
- // At this point we've consumed this file entry
- // ourselves, so just strip the tar footer and
- // go on to the next file in the input stream
- skipTarPadding(info.size, instream);
- return true;
- } else {
- // File data before (or without) the apk. We can't
- // handle it coherently in this case so ignore it.
- mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
- okay = false;
- }
- break;
-
- case ACCEPT:
- if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
- if (DEBUG) Slog.d(TAG, "apk present but ACCEPT");
- // we can take the data without the apk, so we
- // *want* to do so. skip the apk by declaring this
- // one file not-okay without changing the restore
- // policy for the package.
- okay = false;
- }
- break;
-
- default:
- // Something has gone dreadfully wrong when determining
- // the restore policy from the manifest. Ignore the
- // rest of this package's data.
- Slog.e(TAG, "Invalid policy from manifest");
- okay = false;
- mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
- break;
- }
-
- // Is it a *file* we need to drop?
- if (!isRestorableFile(info)) {
- okay = false;
- }
-
- // If the policy is satisfied, go ahead and set up to pipe the
- // data to the agent.
- if (MORE_DEBUG && okay && mAgent != null) {
- Slog.i(TAG, "Reusing existing agent instance");
- }
- if (okay && mAgent == null) {
- if (MORE_DEBUG) Slog.d(TAG, "Need to launch agent for " + pkg);
-
- try {
- mTargetApp = mPackageManager.getApplicationInfo(pkg, 0);
-
- // If we haven't sent any data to this app yet, we probably
- // need to clear it first. Check that.
- if (!mClearedPackages.contains(pkg)) {
- // apps with their own backup agents are
- // responsible for coherently managing a full
- // restore.
- if (mTargetApp.backupAgentName == null) {
- if (DEBUG) Slog.d(TAG, "Clearing app data preparatory to full restore");
- clearApplicationDataSynchronous(pkg);
- } else {
- if (MORE_DEBUG) Slog.d(TAG, "backup agent ("
- + mTargetApp.backupAgentName + ") => no clear");
- }
- mClearedPackages.add(pkg);
- } else {
- if (MORE_DEBUG) {
- Slog.d(TAG, "We've initialized this app already; no clear required");
- }
- }
-
- // All set; now set up the IPC and launch the agent
- setUpPipes();
- mAgent = bindToAgentSynchronous(mTargetApp,
- ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL);
- mAgentPackage = pkg;
- } catch (IOException e) {
- // fall through to error handling
- } catch (NameNotFoundException e) {
- // fall through to error handling
- }
-
- if (mAgent == null) {
- Slog.e(TAG, "Unable to create agent for " + pkg);
- okay = false;
- tearDownPipes();
- mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
- }
- }
-
- // Sanity check: make sure we never give data to the wrong app. This
- // should never happen but a little paranoia here won't go amiss.
- if (okay && !pkg.equals(mAgentPackage)) {
- Slog.e(TAG, "Restoring data for " + pkg
- + " but agent is for " + mAgentPackage);
- okay = false;
- }
-
- // At this point we have an agent ready to handle the full
- // restore data as well as a pipe for sending data to
- // that agent. Tell the agent to start reading from the
- // pipe.
- if (okay) {
- boolean agentSuccess = true;
- long toCopy = info.size;
- try {
- prepareOperationTimeout(mEphemeralOpToken,
- TIMEOUT_FULL_BACKUP_INTERVAL, mMonitorTask,
- OP_TYPE_RESTORE_WAIT);
-
- if (info.domain.equals(FullBackup.OBB_TREE_TOKEN)) {
- if (DEBUG) Slog.d(TAG, "Restoring OBB file for " + pkg
- + " : " + info.path);
- mObbConnection.restoreObbFile(pkg, mPipes[0],
- info.size, info.type, info.path, info.mode,
- info.mtime, mEphemeralOpToken, mBackupManagerBinder);
- } else {
- if (MORE_DEBUG) Slog.d(TAG, "Invoking agent to restore file "
- + info.path);
- // fire up the app's agent listening on the socket. If
- // the agent is running in the system process we can't
- // just invoke it asynchronously, so we provide a thread
- // for it here.
- if (mTargetApp.processName.equals("system")) {
- Slog.d(TAG, "system process agent - spinning a thread");
- RestoreFileRunnable runner = new RestoreFileRunnable(
- mAgent, info, mPipes[0], mEphemeralOpToken);
- new Thread(runner, "restore-sys-runner").start();
- } else {
- mAgent.doRestoreFile(mPipes[0], info.size, info.type,
- info.domain, info.path, info.mode, info.mtime,
- mEphemeralOpToken, mBackupManagerBinder);
- }
- }
- } catch (IOException e) {
- // couldn't dup the socket for a process-local restore
- Slog.d(TAG, "Couldn't establish restore");
- agentSuccess = false;
- okay = false;
- } catch (RemoteException e) {
- // whoops, remote entity went away. We'll eat the content
- // ourselves, then, and not copy it over.
- Slog.e(TAG, "Agent crashed during full restore");
- agentSuccess = false;
- okay = false;
- }
-
- // Copy over the data if the agent is still good
- if (okay) {
- if (MORE_DEBUG) {
- Slog.v(TAG, " copying to restore agent: "
- + toCopy + " bytes");
- }
- boolean pipeOkay = true;
- FileOutputStream pipe = new FileOutputStream(
- mPipes[1].getFileDescriptor());
- while (toCopy > 0) {
- int toRead = (toCopy > mBuffer.length)
- ? mBuffer.length : (int)toCopy;
- int nRead = instream.read(mBuffer, 0, toRead);
- if (nRead >= 0) mBytes += nRead;
- if (nRead <= 0) break;
- toCopy -= nRead;
-
- // send it to the output pipe as long as things
- // are still good
- if (pipeOkay) {
- try {
- pipe.write(mBuffer, 0, nRead);
- } catch (IOException e) {
- Slog.e(TAG, "Failed to write to restore pipe: "
- + e.getMessage());
- pipeOkay = false;
- }
- }
- }
-
- // done sending that file! Now we just need to consume
- // the delta from info.size to the end of block.
- skipTarPadding(info.size, instream);
-
- // and now that we've sent it all, wait for the remote
- // side to acknowledge receipt
- agentSuccess = waitUntilOperationComplete(mEphemeralOpToken);
- }
-
- // okay, if the remote end failed at any point, deal with
- // it by ignoring the rest of the restore on it
- if (!agentSuccess) {
- Slog.w(TAG, "Agent failure; ending restore");
- mBackupHandler.removeMessages(MSG_RESTORE_OPERATION_TIMEOUT);
- tearDownPipes();
- tearDownAgent(mTargetApp);
- mAgent = null;
- mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
-
- // If this was a single-package restore, we halt immediately
- // with an agent error under these circumstances
- if (mOnlyPackage != null) {
- setResult(RestoreEngine.TARGET_FAILURE);
- setRunning(false);
- return false;
- }
- }
- }
-
- // Problems setting up the agent communication, an explicitly
- // dropped file, or an already-ignored package: skip to the
- // next stream entry by reading and discarding this file.
- if (!okay) {
- if (MORE_DEBUG) Slog.d(TAG, "[discarding file content]");
- long bytesToConsume = (info.size + 511) & ~511;
- while (bytesToConsume > 0) {
- int toRead = (bytesToConsume > mBuffer.length)
- ? mBuffer.length : (int)bytesToConsume;
- long nRead = instream.read(mBuffer, 0, toRead);
- if (nRead >= 0) mBytes += nRead;
- if (nRead <= 0) break;
- bytesToConsume -= nRead;
- }
- }
- }
- }
- } catch (IOException e) {
- if (DEBUG) Slog.w(TAG, "io exception on restore socket read: " + e.getMessage());
- setResult(RestoreEngine.TRANSPORT_FAILURE);
- info = null;
- }
-
- // If we got here we're either running smoothly or we've finished
- if (info == null) {
- if (MORE_DEBUG) {
- Slog.i(TAG, "No [more] data for this package; tearing down");
- }
- tearDownPipes();
- setRunning(false);
- if (mustKillAgent) {
- tearDownAgent(mTargetApp);
- }
- }
- return (info != null);
- }
-
- void setUpPipes() throws IOException {
- mPipes = ParcelFileDescriptor.createPipe();
- }
-
- void tearDownPipes() {
- // Teardown might arise from the inline restore processing or from the asynchronous
- // timeout mechanism, and these might race. Make sure we don't try to close and
- // null out the pipes twice.
- synchronized (this) {
- if (mPipes != null) {
- try {
- mPipes[0].close();
- mPipes[0] = null;
- mPipes[1].close();
- mPipes[1] = null;
- } catch (IOException e) {
- Slog.w(TAG, "Couldn't close agent pipes", e);
- }
- mPipes = null;
- }
- }
- }
-
- void tearDownAgent(ApplicationInfo app) {
- if (mAgent != null) {
- tearDownAgentAndKill(app);
- mAgent = null;
- }
- }
-
- void handleTimeout() {
- tearDownPipes();
- setResult(RestoreEngine.TARGET_FAILURE);
- setRunning(false);
- }
-
- class RestoreInstallObserver extends PackageInstallObserver {
- final AtomicBoolean mDone = new AtomicBoolean();
- String mPackageName;
- int mResult;
-
- public void reset() {
- synchronized (mDone) {
- mDone.set(false);
- }
- }
-
- public void waitForCompletion() {
- synchronized (mDone) {
- while (mDone.get() == false) {
- try {
- mDone.wait();
- } catch (InterruptedException e) { }
- }
- }
- }
-
- int getResult() {
- return mResult;
- }
-
- @Override
- public void onPackageInstalled(String packageName, int returnCode,
- String msg, Bundle extras) {
- synchronized (mDone) {
- mResult = returnCode;
- mPackageName = packageName;
- mDone.set(true);
- mDone.notifyAll();
- }
- }
- }
-
- class RestoreDeleteObserver extends IPackageDeleteObserver.Stub {
- final AtomicBoolean mDone = new AtomicBoolean();
- int mResult;
-
- public void reset() {
- synchronized (mDone) {
- mDone.set(false);
- }
- }
-
- public void waitForCompletion() {
- synchronized (mDone) {
- while (mDone.get() == false) {
- try {
- mDone.wait();
- } catch (InterruptedException e) { }
- }
- }
- }
-
- @Override
- public void packageDeleted(String packageName, int returnCode) throws RemoteException {
- synchronized (mDone) {
- mResult = returnCode;
- mDone.set(true);
- mDone.notifyAll();
- }
- }
- }
-
- final RestoreInstallObserver mInstallObserver = new RestoreInstallObserver();
- final RestoreDeleteObserver mDeleteObserver = new RestoreDeleteObserver();
-
- boolean installApk(FileMetadata info, String installerPackage, InputStream instream) {
- boolean okay = true;
-
- if (DEBUG) Slog.d(TAG, "Installing from backup: " + info.packageName);
-
- // The file content is an .apk file. Copy it out to a staging location and
- // attempt to install it.
- File apkFile = new File(mDataDir, info.packageName);
- try {
- FileOutputStream apkStream = new FileOutputStream(apkFile);
- byte[] buffer = new byte[32 * 1024];
- long size = info.size;
- while (size > 0) {
- long toRead = (buffer.length < size) ? buffer.length : size;
- int didRead = instream.read(buffer, 0, (int)toRead);
- if (didRead >= 0) mBytes += didRead;
- apkStream.write(buffer, 0, didRead);
- size -= didRead;
- }
- apkStream.close();
-
- // make sure the installer can read it
- apkFile.setReadable(true, false);
-
- // Now install it
- Uri packageUri = Uri.fromFile(apkFile);
- mInstallObserver.reset();
- mPackageManager.installPackage(packageUri, mInstallObserver,
- PackageManager.INSTALL_REPLACE_EXISTING | PackageManager.INSTALL_FROM_ADB,
- installerPackage);
- mInstallObserver.waitForCompletion();
-
- if (mInstallObserver.getResult() != PackageManager.INSTALL_SUCCEEDED) {
- // The only time we continue to accept install of data even if the
- // apk install failed is if we had already determined that we could
- // accept the data regardless.
- if (mPackagePolicies.get(info.packageName) != RestorePolicy.ACCEPT) {
- okay = false;
- }
- } else {
- // Okay, the install succeeded. Make sure it was the right app.
- boolean uninstall = false;
- if (!mInstallObserver.mPackageName.equals(info.packageName)) {
- Slog.w(TAG, "Restore stream claimed to include apk for "
- + info.packageName + " but apk was really "
- + mInstallObserver.mPackageName);
- // delete the package we just put in place; it might be fraudulent
- okay = false;
- uninstall = true;
- } else {
- try {
- PackageInfo pkg = mPackageManager.getPackageInfo(info.packageName,
- PackageManager.GET_SIGNATURES);
- if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
- Slog.w(TAG, "Restore stream contains apk of package "
- + info.packageName + " but it disallows backup/restore");
- okay = false;
- } else {
- // So far so good -- do the signatures match the manifest?
- Signature[] sigs = mManifestSignatures.get(info.packageName);
- if (signaturesMatch(sigs, pkg)) {
- // If this is a system-uid app without a declared backup agent,
- // don't restore any of the file data.
- if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
- && (pkg.applicationInfo.backupAgentName == null)) {
- Slog.w(TAG, "Installed app " + info.packageName
- + " has restricted uid and no agent");
- okay = false;
- }
- } else {
- Slog.w(TAG, "Installed app " + info.packageName
- + " signatures do not match restore manifest");
- okay = false;
- uninstall = true;
- }
- }
- } catch (NameNotFoundException e) {
- Slog.w(TAG, "Install of package " + info.packageName
- + " succeeded but now not found");
- okay = false;
- }
- }
-
- // If we're not okay at this point, we need to delete the package
- // that we just installed.
- if (uninstall) {
- mDeleteObserver.reset();
- mPackageManager.deletePackage(mInstallObserver.mPackageName,
- mDeleteObserver, 0);
- mDeleteObserver.waitForCompletion();
- }
- }
- } catch (IOException e) {
- Slog.e(TAG, "Unable to transcribe restored apk for install");
- okay = false;
- } finally {
- apkFile.delete();
- }
-
- return okay;
- }
-
- // Given an actual file content size, consume the post-content padding mandated
- // by the tar format.
- void skipTarPadding(long size, InputStream instream) throws IOException {
- long partial = (size + 512) % 512;
- if (partial > 0) {
- final int needed = 512 - (int)partial;
- if (MORE_DEBUG) {
- Slog.i(TAG, "Skipping tar padding: " + needed + " bytes");
- }
- byte[] buffer = new byte[needed];
- if (readExactly(instream, buffer, 0, needed) == needed) {
- mBytes += needed;
- } else throw new IOException("Unexpected EOF in padding");
- }
- }
-
- // Read a widget metadata file, returning the restored blob
- void readMetadata(FileMetadata info, InputStream instream) throws IOException {
- // Fail on suspiciously large widget dump files
- if (info.size > 64 * 1024) {
- throw new IOException("Metadata too big; corrupt? size=" + info.size);
- }
-
- byte[] buffer = new byte[(int) info.size];
- if (readExactly(instream, buffer, 0, (int)info.size) == info.size) {
- mBytes += info.size;
- } else throw new IOException("Unexpected EOF in widget data");
-
- String[] str = new String[1];
- int offset = extractLine(buffer, 0, str);
- int version = Integer.parseInt(str[0]);
- if (version == BACKUP_MANIFEST_VERSION) {
- offset = extractLine(buffer, offset, str);
- final String pkg = str[0];
- if (info.packageName.equals(pkg)) {
- // Data checks out -- the rest of the buffer is a concatenation of
- // binary blobs as described in the comment at writeAppWidgetData()
- ByteArrayInputStream bin = new ByteArrayInputStream(buffer,
- offset, buffer.length - offset);
- DataInputStream in = new DataInputStream(bin);
- while (bin.available() > 0) {
- int token = in.readInt();
- int size = in.readInt();
- if (size > 64 * 1024) {
- throw new IOException("Datum "
- + Integer.toHexString(token)
- + " too big; corrupt? size=" + info.size);
- }
- switch (token) {
- case BACKUP_WIDGET_METADATA_TOKEN:
- {
- if (MORE_DEBUG) {
- Slog.i(TAG, "Got widget metadata for " + info.packageName);
- }
- mWidgetData = new byte[size];
- in.read(mWidgetData);
- break;
- }
- default:
- {
- if (DEBUG) {
- Slog.i(TAG, "Ignoring metadata blob "
- + Integer.toHexString(token)
- + " for " + info.packageName);
- }
- in.skipBytes(size);
- break;
- }
- }
- }
- } else {
- Slog.w(TAG, "Metadata mismatch: package " + info.packageName
- + " but widget data for " + pkg);
-
- Bundle monitoringExtras = putMonitoringExtra(null,
- EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
- monitoringExtras = putMonitoringExtra(monitoringExtras,
- BackupManagerMonitor.EXTRA_LOG_WIDGET_PACKAGE_NAME, pkg);
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_WIDGET_METADATA_MISMATCH,
- null,
- LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- monitoringExtras);
- }
- } else {
- Slog.w(TAG, "Unsupported metadata version " + version);
-
- Bundle monitoringExtras = putMonitoringExtra(null, EXTRA_LOG_EVENT_PACKAGE_NAME,
- info.packageName);
- monitoringExtras = putMonitoringExtra(monitoringExtras,
- EXTRA_LOG_EVENT_PACKAGE_VERSION, version);
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_WIDGET_UNKNOWN_VERSION,
- null,
- LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- monitoringExtras);
- }
- }
-
- // Returns a policy constant
- RestorePolicy readAppManifest(FileMetadata info, InputStream instream)
- throws IOException {
- // Fail on suspiciously large manifest files
- if (info.size > 64 * 1024) {
- throw new IOException("Restore manifest too big; corrupt? size=" + info.size);
- }
-
- byte[] buffer = new byte[(int) info.size];
- if (MORE_DEBUG) {
- Slog.i(TAG, " readAppManifest() looking for " + info.size + " bytes, "
- + mBytes + " already consumed");
- }
- if (readExactly(instream, buffer, 0, (int)info.size) == info.size) {
- mBytes += info.size;
- } else throw new IOException("Unexpected EOF in manifest");
-
- RestorePolicy policy = RestorePolicy.IGNORE;
- String[] str = new String[1];
- int offset = 0;
-
- try {
- offset = extractLine(buffer, offset, str);
- int version = Integer.parseInt(str[0]);
- if (version == BACKUP_MANIFEST_VERSION) {
- offset = extractLine(buffer, offset, str);
- String manifestPackage = str[0];
- // TODO: handle <original-package>
- if (manifestPackage.equals(info.packageName)) {
- offset = extractLine(buffer, offset, str);
- version = Integer.parseInt(str[0]); // app version
- offset = extractLine(buffer, offset, str);
- // This is the platform version, which we don't use, but we parse it
- // as a safety against corruption in the manifest.
- Integer.parseInt(str[0]);
- offset = extractLine(buffer, offset, str);
- info.installerPackageName = (str[0].length() > 0) ? str[0] : null;
- offset = extractLine(buffer, offset, str);
- boolean hasApk = str[0].equals("1");
- offset = extractLine(buffer, offset, str);
- int numSigs = Integer.parseInt(str[0]);
- if (numSigs > 0) {
- Signature[] sigs = new Signature[numSigs];
- for (int i = 0; i < numSigs; i++) {
- offset = extractLine(buffer, offset, str);
- sigs[i] = new Signature(str[0]);
- }
- mManifestSignatures.put(info.packageName, sigs);
-
- // Okay, got the manifest info we need...
- try {
- PackageInfo pkgInfo = mPackageManager.getPackageInfo(
- info.packageName, PackageManager.GET_SIGNATURES);
- // Fall through to IGNORE if the app explicitly disallows backup
- final int flags = pkgInfo.applicationInfo.flags;
- if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
- // Restore system-uid-space packages only if they have
- // defined a custom backup agent
- if ((pkgInfo.applicationInfo.uid >= Process.FIRST_APPLICATION_UID)
- || (pkgInfo.applicationInfo.backupAgentName != null)) {
- // Verify signatures against any installed version; if they
- // don't match, then we fall though and ignore the data. The
- // signatureMatch() method explicitly ignores the signature
- // check for packages installed on the system partition, because
- // such packages are signed with the platform cert instead of
- // the app developer's cert, so they're different on every
- // device.
- if (signaturesMatch(sigs, pkgInfo)) {
- if ((pkgInfo.applicationInfo.flags
- & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
- Slog.i(TAG, "Package has restoreAnyVersion; taking data");
- mMonitor = monitorEvent(mMonitor,
- LOG_EVENT_ID_RESTORE_ANY_VERSION,
- pkgInfo,
- LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- null);
- policy = RestorePolicy.ACCEPT;
- } else if (pkgInfo.versionCode >= version) {
- Slog.i(TAG, "Sig + version match; taking data");
- policy = RestorePolicy.ACCEPT;
- mMonitor = monitorEvent(mMonitor,
- LOG_EVENT_ID_VERSIONS_MATCH,
- pkgInfo,
- LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- null);
- } else {
- // The data is from a newer version of the app than
- // is presently installed. That means we can only
- // use it if the matching apk is also supplied.
- if (mAllowApks) {
- Slog.i(TAG, "Data version " + version
- + " is newer than installed version "
- + pkgInfo.versionCode
- + " - requiring apk");
- policy = RestorePolicy.ACCEPT_IF_APK;
- } else {
- Slog.i(TAG, "Data requires newer version "
- + version + "; ignoring");
- mMonitor = monitorEvent(mMonitor,
- LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER,
- pkgInfo,
- LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- putMonitoringExtra(null,
- EXTRA_LOG_OLD_VERSION,
- version));
-
- policy = RestorePolicy.IGNORE;
- }
- }
- } else {
- Slog.w(TAG, "Restore manifest signatures do not match "
- + "installed application for " + info.packageName);
- mMonitor = monitorEvent(mMonitor,
- LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH,
- pkgInfo,
- LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- null);
- }
- } else {
- Slog.w(TAG, "Package " + info.packageName
- + " is system level with no agent");
- mMonitor = monitorEvent(mMonitor,
- LOG_EVENT_ID_SYSTEM_APP_NO_AGENT,
- pkgInfo,
- LOG_EVENT_CATEGORY_AGENT,
- null);
- }
- } else {
- if (DEBUG) Slog.i(TAG, "Restore manifest from "
- + info.packageName + " but allowBackup=false");
- mMonitor = monitorEvent(mMonitor,
- LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE,
- pkgInfo,
- LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- null);
- }
- } catch (NameNotFoundException e) {
- // Okay, the target app isn't installed. We can process
- // the restore properly only if the dataset provides the
- // apk file and we can successfully install it.
- if (mAllowApks) {
- if (DEBUG) Slog.i(TAG, "Package " + info.packageName
- + " not installed; requiring apk in dataset");
- policy = RestorePolicy.ACCEPT_IF_APK;
- } else {
- policy = RestorePolicy.IGNORE;
- }
- Bundle monitoringExtras = putMonitoringExtra(null,
- EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
- monitoringExtras = putMonitoringExtra(monitoringExtras,
- EXTRA_LOG_POLICY_ALLOW_APKS, mAllowApks);
- mMonitor = monitorEvent(mMonitor,
- LOG_EVENT_ID_APK_NOT_INSTALLED,
- null,
- LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- monitoringExtras);
- }
-
- if (policy == RestorePolicy.ACCEPT_IF_APK && !hasApk) {
- Slog.i(TAG, "Cannot restore package " + info.packageName
- + " without the matching .apk");
- mMonitor = monitorEvent(mMonitor,
- LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK,
- null,
- LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- putMonitoringExtra(null,
- EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName));
- }
- } else {
- Slog.i(TAG, "Missing signature on backed-up package "
- + info.packageName);
- mMonitor = monitorEvent(mMonitor,
- LOG_EVENT_ID_MISSING_SIGNATURE,
- null,
- LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- putMonitoringExtra(null,
- EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName));
- }
- } else {
- Slog.i(TAG, "Expected package " + info.packageName
- + " but restore manifest claims " + manifestPackage);
- Bundle monitoringExtras = putMonitoringExtra(null,
- EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
- monitoringExtras = putMonitoringExtra(monitoringExtras,
- EXTRA_LOG_MANIFEST_PACKAGE_NAME, manifestPackage);
- mMonitor = monitorEvent(mMonitor,
- LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE,
- null,
- LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- monitoringExtras);
- }
- } else {
- Slog.i(TAG, "Unknown restore manifest version " + version
- + " for package " + info.packageName);
- Bundle monitoringExtras = putMonitoringExtra(null,
- EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
- monitoringExtras = putMonitoringExtra(monitoringExtras,
- EXTRA_LOG_EVENT_PACKAGE_VERSION, version);
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_UNKNOWN_VERSION,
- null,
- LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- monitoringExtras);
-
- }
- } catch (NumberFormatException e) {
- Slog.w(TAG, "Corrupt restore manifest for package " + info.packageName);
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_CORRUPT_MANIFEST,
- null,
- LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- putMonitoringExtra(null, EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName));
- } catch (IllegalArgumentException e) {
- Slog.w(TAG, e.getMessage());
- }
-
- return policy;
- }
-
- // Builds a line from a byte buffer starting at 'offset', and returns
- // the index of the next unconsumed data in the buffer.
- int extractLine(byte[] buffer, int offset, String[] outStr) throws IOException {
- final int end = buffer.length;
- if (offset >= end) throw new IOException("Incomplete data");
-
- int pos;
- for (pos = offset; pos < end; pos++) {
- byte c = buffer[pos];
- // at LF we declare end of line, and return the next char as the
- // starting point for the next time through
- if (c == '\n') {
- break;
- }
- }
- outStr[0] = new String(buffer, offset, pos - offset);
- pos++; // may be pointing an extra byte past the end but that's okay
- return pos;
- }
-
- void dumpFileMetadata(FileMetadata info) {
- if (MORE_DEBUG) {
- StringBuilder b = new StringBuilder(128);
-
- // mode string
- b.append((info.type == BackupAgent.TYPE_DIRECTORY) ? 'd' : '-');
- b.append(((info.mode & 0400) != 0) ? 'r' : '-');
- b.append(((info.mode & 0200) != 0) ? 'w' : '-');
- b.append(((info.mode & 0100) != 0) ? 'x' : '-');
- b.append(((info.mode & 0040) != 0) ? 'r' : '-');
- b.append(((info.mode & 0020) != 0) ? 'w' : '-');
- b.append(((info.mode & 0010) != 0) ? 'x' : '-');
- b.append(((info.mode & 0004) != 0) ? 'r' : '-');
- b.append(((info.mode & 0002) != 0) ? 'w' : '-');
- b.append(((info.mode & 0001) != 0) ? 'x' : '-');
- b.append(String.format(" %9d ", info.size));
-
- Date stamp = new Date(info.mtime);
- b.append(new SimpleDateFormat("MMM dd HH:mm:ss ").format(stamp));
-
- b.append(info.packageName);
- b.append(" :: ");
- b.append(info.domain);
- b.append(" :: ");
- b.append(info.path);
-
- Slog.i(TAG, b.toString());
- }
- }
-
- // Consume a tar file header block [sequence] and accumulate the relevant metadata
- FileMetadata readTarHeaders(InputStream instream) throws IOException {
- byte[] block = new byte[512];
- FileMetadata info = null;
-
- boolean gotHeader = readTarHeader(instream, block);
- if (gotHeader) {
- try {
- // okay, presume we're okay, and extract the various metadata
- info = new FileMetadata();
- info.size = extractRadix(block, TAR_HEADER_OFFSET_FILESIZE,
- TAR_HEADER_LENGTH_FILESIZE, TAR_HEADER_LONG_RADIX);
- info.mtime = extractRadix(block, TAR_HEADER_OFFSET_MODTIME,
- TAR_HEADER_LENGTH_MODTIME, TAR_HEADER_LONG_RADIX);
- info.mode = extractRadix(block, TAR_HEADER_OFFSET_MODE,
- TAR_HEADER_LENGTH_MODE, TAR_HEADER_LONG_RADIX);
-
- info.path = extractString(block, TAR_HEADER_OFFSET_PATH_PREFIX,
- TAR_HEADER_LENGTH_PATH_PREFIX);
- String path = extractString(block, TAR_HEADER_OFFSET_PATH,
- TAR_HEADER_LENGTH_PATH);
- if (path.length() > 0) {
- if (info.path.length() > 0) info.path += '/';
- info.path += path;
- }
-
- // tar link indicator field: 1 byte at offset 156 in the header.
- int typeChar = block[TAR_HEADER_OFFSET_TYPE_CHAR];
- if (typeChar == 'x') {
- // pax extended header, so we need to read that
- gotHeader = readPaxExtendedHeader(instream, info);
- if (gotHeader) {
- // and after a pax extended header comes another real header -- read
- // that to find the real file type
- gotHeader = readTarHeader(instream, block);
- }
- if (!gotHeader) throw new IOException("Bad or missing pax header");
-
- typeChar = block[TAR_HEADER_OFFSET_TYPE_CHAR];
- }
-
- switch (typeChar) {
- case '0': info.type = BackupAgent.TYPE_FILE; break;
- case '5': {
- info.type = BackupAgent.TYPE_DIRECTORY;
- if (info.size != 0) {
- Slog.w(TAG, "Directory entry with nonzero size in header");
- info.size = 0;
- }
- break;
- }
- case 0: {
- // presume EOF
- if (MORE_DEBUG) Slog.w(TAG, "Saw type=0 in tar header block, info=" + info);
- return null;
- }
- default: {
- Slog.e(TAG, "Unknown tar entity type: " + typeChar);
- throw new IOException("Unknown entity type " + typeChar);
- }
- }
-
- // Parse out the path
- //
- // first: apps/shared/unrecognized
- if (FullBackup.SHARED_PREFIX.regionMatches(0,
- info.path, 0, FullBackup.SHARED_PREFIX.length())) {
- // File in shared storage. !!! TODO: implement this.
- info.path = info.path.substring(FullBackup.SHARED_PREFIX.length());
- info.packageName = SHARED_BACKUP_AGENT_PACKAGE;
- info.domain = FullBackup.SHARED_STORAGE_TOKEN;
- if (DEBUG) Slog.i(TAG, "File in shared storage: " + info.path);
- } else if (FullBackup.APPS_PREFIX.regionMatches(0,
- info.path, 0, FullBackup.APPS_PREFIX.length())) {
- // App content! Parse out the package name and domain
-
- // strip the apps/ prefix
- info.path = info.path.substring(FullBackup.APPS_PREFIX.length());
-
- // extract the package name
- int slash = info.path.indexOf('/');
- if (slash < 0) throw new IOException("Illegal semantic path in " + info.path);
- info.packageName = info.path.substring(0, slash);
- info.path = info.path.substring(slash+1);
-
- // if it's a manifest or metadata payload we're done, otherwise parse
- // out the domain into which the file will be restored
- if (!info.path.equals(BACKUP_MANIFEST_FILENAME)
- && !info.path.equals(BACKUP_METADATA_FILENAME)) {
- slash = info.path.indexOf('/');
- if (slash < 0) {
- throw new IOException("Illegal semantic path in non-manifest "
- + info.path);
- }
- info.domain = info.path.substring(0, slash);
- info.path = info.path.substring(slash + 1);
- }
- }
- } catch (IOException e) {
- if (DEBUG) {
- Slog.e(TAG, "Parse error in header: " + e.getMessage());
- if (MORE_DEBUG) {
- HEXLOG(block);
- }
- }
- throw e;
- }
- }
- return info;
- }
-
- private boolean isRestorableFile(FileMetadata info) {
- if (FullBackup.CACHE_TREE_TOKEN.equals(info.domain)) {
- if (MORE_DEBUG) {
- Slog.i(TAG, "Dropping cache file path " + info.path);
- }
- return false;
- }
-
- if (FullBackup.ROOT_TREE_TOKEN.equals(info.domain)) {
- // It's possible this is "no-backup" dir contents in an archive stream
- // produced on a device running a version of the OS that predates that
- // API. Respect the no-backup intention and don't let the data get to
- // the app.
- if (info.path.startsWith("no_backup/")) {
- if (MORE_DEBUG) {
- Slog.i(TAG, "Dropping no_backup file path " + info.path);
- }
- return false;
- }
- }
-
- // The path needs to be canonical
- if (info.path.contains("..") || info.path.contains("//")) {
- if (MORE_DEBUG) {
- Slog.w(TAG, "Dropping invalid path " + info.path);
- }
- return false;
- }
-
- // Otherwise we think this file is good to go
- return true;
- }
-
- private void HEXLOG(byte[] block) {
- int offset = 0;
- int todo = block.length;
- StringBuilder buf = new StringBuilder(64);
- while (todo > 0) {
- buf.append(String.format("%04x ", offset));
- int numThisLine = (todo > 16) ? 16 : todo;
- for (int i = 0; i < numThisLine; i++) {
- buf.append(String.format("%02x ", block[offset+i]));
- }
- Slog.i("hexdump", buf.toString());
- buf.setLength(0);
- todo -= numThisLine;
- offset += numThisLine;
- }
- }
-
- // Read exactly the given number of bytes into a buffer at the stated offset.
- // Returns false if EOF is encountered before the requested number of bytes
- // could be read.
- int readExactly(InputStream in, byte[] buffer, int offset, int size)
- throws IOException {
- if (size <= 0) throw new IllegalArgumentException("size must be > 0");
-if (MORE_DEBUG) Slog.i(TAG, " ... readExactly(" + size + ") called");
- int soFar = 0;
- while (soFar < size) {
- int nRead = in.read(buffer, offset + soFar, size - soFar);
- if (nRead <= 0) {
- if (MORE_DEBUG) Slog.w(TAG, "- wanted exactly " + size + " but got only " + soFar);
- break;
- }
- soFar += nRead;
-if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soFar));
- }
- return soFar;
- }
-
- boolean readTarHeader(InputStream instream, byte[] block) throws IOException {
- final int got = readExactly(instream, block, 0, 512);
- if (got == 0) return false; // Clean EOF
- if (got < 512) throw new IOException("Unable to read full block header");
- mBytes += 512;
- return true;
- }
-
- // overwrites 'info' fields based on the pax extended header
- boolean readPaxExtendedHeader(InputStream instream, FileMetadata info)
- throws IOException {
- // We should never see a pax extended header larger than this
- if (info.size > 32*1024) {
- Slog.w(TAG, "Suspiciously large pax header size " + info.size
- + " - aborting");
- throw new IOException("Sanity failure: pax header size " + info.size);
- }
-
- // read whole blocks, not just the content size
- int numBlocks = (int)((info.size + 511) >> 9);
- byte[] data = new byte[numBlocks * 512];
- if (readExactly(instream, data, 0, data.length) < data.length) {
- throw new IOException("Unable to read full pax header");
- }
- mBytes += data.length;
-
- final int contentSize = (int) info.size;
- int offset = 0;
- do {
- // extract the line at 'offset'
- int eol = offset+1;
- while (eol < contentSize && data[eol] != ' ') eol++;
- if (eol >= contentSize) {
- // error: we just hit EOD looking for the end of the size field
- throw new IOException("Invalid pax data");
- }
- // eol points to the space between the count and the key
- int linelen = (int) extractRadix(data, offset, eol - offset, 10);
- int key = eol + 1; // start of key=value
- eol = offset + linelen - 1; // trailing LF
- int value;
- for (value = key+1; data[value] != '=' && value <= eol; value++);
- if (value > eol) {
- throw new IOException("Invalid pax declaration");
- }
-
- // pax requires that key/value strings be in UTF-8
- String keyStr = new String(data, key, value-key, "UTF-8");
- // -1 to strip the trailing LF
- String valStr = new String(data, value+1, eol-value-1, "UTF-8");
-
- if ("path".equals(keyStr)) {
- info.path = valStr;
- } else if ("size".equals(keyStr)) {
- info.size = Long.parseLong(valStr);
- } else {
- if (DEBUG) Slog.i(TAG, "Unhandled pax key: " + key);
- }
-
- offset += linelen;
- } while (offset < contentSize);
-
- return true;
- }
-
- long extractRadix(byte[] data, int offset, int maxChars, int radix)
- throws IOException {
- long value = 0;
- final int end = offset + maxChars;
- for (int i = offset; i < end; i++) {
- final byte b = data[i];
- // Numeric fields in tar can terminate with either NUL or SPC
- if (b == 0 || b == ' ') break;
- if (b < '0' || b > ('0' + radix - 1)) {
- throw new IOException("Invalid number in header: '" + (char)b
- + "' for radix " + radix);
- }
- value = radix * value + (b - '0');
- }
- return value;
- }
-
- String extractString(byte[] data, int offset, int maxChars) throws IOException {
- final int end = offset + maxChars;
- int eos = offset;
- // tar string fields terminate early with a NUL
- while (eos < end && data[eos] != 0) eos++;
- return new String(data, offset, eos-offset, "US-ASCII");
- }
-
- void sendStartRestore() {
- if (mObserver != null) {
- try {
- mObserver.onStartRestore();
- } catch (RemoteException e) {
- Slog.w(TAG, "full restore observer went away: startRestore");
- mObserver = null;
- }
- }
- }
-
- void sendOnRestorePackage(String name) {
- if (mObserver != null) {
- try {
- // TODO: use a more user-friendly name string
- mObserver.onRestorePackage(name);
- } catch (RemoteException e) {
- Slog.w(TAG, "full restore observer went away: restorePackage");
- mObserver = null;
- }
- }
- }
-
- void sendEndRestore() {
- if (mObserver != null) {
- try {
- mObserver.onEndRestore();
- } catch (RemoteException e) {
- Slog.w(TAG, "full restore observer went away: endRestore");
- mObserver = null;
- }
- }
- }
- }
-
- // ***** end new engine class ***
-
- // Used for synchronizing doRestoreFinished during adb restore
- class AdbRestoreFinishedLatch implements BackupRestoreTask {
- static final String TAG = "AdbRestoreFinishedLatch";
- final CountDownLatch mLatch;
- private final int mCurrentOpToken;
-
- AdbRestoreFinishedLatch(int currentOpToken) {
- mLatch = new CountDownLatch(1);
- mCurrentOpToken = currentOpToken;
- }
-
- void await() {
- boolean latched = false;
- try {
- latched = mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- Slog.w(TAG, "Interrupted!");
- }
- }
-
- @Override
- public void execute() {
- // Unused
- }
-
- @Override
- public void operationComplete(long result) {
- if (MORE_DEBUG) {
- Slog.w(TAG, "adb onRestoreFinished() complete");
- }
- mLatch.countDown();
- removeOperation(mCurrentOpToken);
- }
-
- @Override
- public void handleCancel(boolean cancelAll) {
- if (DEBUG) {
- Slog.w(TAG, "adb onRestoreFinished() timed out");
- }
- mLatch.countDown();
- removeOperation(mCurrentOpToken);
- }
- }
-
- class PerformAdbRestoreTask implements Runnable {
- ParcelFileDescriptor mInputFile;
- String mCurrentPassword;
- String mDecryptPassword;
- IFullBackupRestoreObserver mObserver;
- AtomicBoolean mLatchObject;
- IBackupAgent mAgent;
- PackageManagerBackupAgent mPackageManagerBackupAgent;
- String mAgentPackage;
- ApplicationInfo mTargetApp;
- FullBackupObbConnection mObbConnection = null;
- ParcelFileDescriptor[] mPipes = null;
- byte[] mWidgetData = null;
-
- long mBytes;
-
- // Runner that can be placed on a separate thread to do in-process invocation
- // of the "restore finished" API asynchronously. Used by adb restore.
- class RestoreFinishedRunnable implements Runnable {
- final IBackupAgent mAgent;
- final int mToken;
-
- RestoreFinishedRunnable(IBackupAgent agent, int token) {
- mAgent = agent;
- mToken = token;
- }
-
- @Override
- public void run() {
- try {
- mAgent.doRestoreFinished(mToken, mBackupManagerBinder);
- } catch (RemoteException e) {
- // never happens; this is used only for local binder calls
- }
- }
- }
-
- // possible handling states for a given package in the restore dataset
- final HashMap<String, RestorePolicy> mPackagePolicies
- = new HashMap<String, RestorePolicy>();
-
- // installer package names for each encountered app, derived from the manifests
- final HashMap<String, String> mPackageInstallers = new HashMap<String, String>();
-
- // Signatures for a given package found in its manifest file
- final HashMap<String, Signature[]> mManifestSignatures
- = new HashMap<String, Signature[]>();
-
- // Packages we've already wiped data on when restoring their first file
- final HashSet<String> mClearedPackages = new HashSet<String>();
-
- PerformAdbRestoreTask(ParcelFileDescriptor fd, String curPassword, String decryptPassword,
- IFullBackupRestoreObserver observer, AtomicBoolean latch) {
- mInputFile = fd;
- mCurrentPassword = curPassword;
- mDecryptPassword = decryptPassword;
- mObserver = observer;
- mLatchObject = latch;
- mAgent = null;
- mPackageManagerBackupAgent = makeMetadataAgent();
- mAgentPackage = null;
- mTargetApp = null;
- mObbConnection = new FullBackupObbConnection();
-
- // Which packages we've already wiped data on. We prepopulate this
- // with a whitelist of packages known to be unclearable.
- mClearedPackages.add("android");
- mClearedPackages.add(SETTINGS_PACKAGE);
- }
-
- class RestoreFileRunnable implements Runnable {
- IBackupAgent mAgent;
- FileMetadata mInfo;
- ParcelFileDescriptor mSocket;
- int mToken;
-
- RestoreFileRunnable(IBackupAgent agent, FileMetadata info,
- ParcelFileDescriptor socket, int token) throws IOException {
- mAgent = agent;
- mInfo = info;
- mToken = token;
-
- // This class is used strictly for process-local binder invocations. The
- // semantics of ParcelFileDescriptor differ in this case; in particular, we
- // do not automatically get a 'dup'ed descriptor that we can can continue
- // to use asynchronously from the caller. So, we make sure to dup it ourselves
- // before proceeding to do the restore.
- mSocket = ParcelFileDescriptor.dup(socket.getFileDescriptor());
- }
-
- @Override
- public void run() {
- try {
- mAgent.doRestoreFile(mSocket, mInfo.size, mInfo.type,
- mInfo.domain, mInfo.path, mInfo.mode, mInfo.mtime,
- mToken, mBackupManagerBinder);
- } catch (RemoteException e) {
- // never happens; this is used strictly for local binder calls
- }
- }
- }
-
- @Override
- public void run() {
- Slog.i(TAG, "--- Performing full-dataset restore ---");
- mObbConnection.establish();
- sendStartRestore();
-
- // Are we able to restore shared-storage data?
- if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- mPackagePolicies.put(SHARED_BACKUP_AGENT_PACKAGE, RestorePolicy.ACCEPT);
- }
-
- FileInputStream rawInStream = null;
- DataInputStream rawDataIn = null;
- try {
- if (!backupPasswordMatches(mCurrentPassword)) {
- if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
- return;
- }
-
- mBytes = 0;
- byte[] buffer = new byte[32 * 1024];
- rawInStream = new FileInputStream(mInputFile.getFileDescriptor());
- rawDataIn = new DataInputStream(rawInStream);
-
- // First, parse out the unencrypted/uncompressed header
- boolean compressed = false;
- InputStream preCompressStream = rawInStream;
- final InputStream in;
-
- boolean okay = false;
- final int headerLen = BACKUP_FILE_HEADER_MAGIC.length();
- byte[] streamHeader = new byte[headerLen];
- rawDataIn.readFully(streamHeader);
- byte[] magicBytes = BACKUP_FILE_HEADER_MAGIC.getBytes("UTF-8");
- if (Arrays.equals(magicBytes, streamHeader)) {
- // okay, header looks good. now parse out the rest of the fields.
- String s = readHeaderLine(rawInStream);
- final int archiveVersion = Integer.parseInt(s);
- if (archiveVersion <= BACKUP_FILE_VERSION) {
- // okay, it's a version we recognize. if it's version 1, we may need
- // to try two different PBKDF2 regimes to compare checksums.
- final boolean pbkdf2Fallback = (archiveVersion == 1);
-
- s = readHeaderLine(rawInStream);
- compressed = (Integer.parseInt(s) != 0);
- s = readHeaderLine(rawInStream);
- if (s.equals("none")) {
- // no more header to parse; we're good to go
- okay = true;
- } else if (mDecryptPassword != null && mDecryptPassword.length() > 0) {
- preCompressStream = decodeAesHeaderAndInitialize(s, pbkdf2Fallback,
- rawInStream);
- if (preCompressStream != null) {
- okay = true;
- }
- } else Slog.w(TAG, "Archive is encrypted but no password given");
- } else Slog.w(TAG, "Wrong header version: " + s);
- } else Slog.w(TAG, "Didn't read the right header magic");
-
- if (!okay) {
- Slog.w(TAG, "Invalid restore data; aborting.");
- return;
- }
-
- // okay, use the right stream layer based on compression
- in = (compressed) ? new InflaterInputStream(preCompressStream) : preCompressStream;
-
- boolean didRestore;
- do {
- didRestore = restoreOneFile(in, buffer);
- } while (didRestore);
-
- if (MORE_DEBUG) Slog.v(TAG, "Done consuming input tarfile, total bytes=" + mBytes);
- } catch (IOException e) {
- Slog.e(TAG, "Unable to read restore input");
- } finally {
- tearDownPipes();
- tearDownAgent(mTargetApp, true);
-
- try {
- if (rawDataIn != null) rawDataIn.close();
- if (rawInStream != null) rawInStream.close();
- mInputFile.close();
- } catch (IOException e) {
- Slog.w(TAG, "Close of restore data pipe threw", e);
- /* nothing we can do about this */
- }
- synchronized (mLatchObject) {
- mLatchObject.set(true);
- mLatchObject.notifyAll();
- }
- mObbConnection.tearDown();
- sendEndRestore();
- Slog.d(TAG, "Full restore pass complete.");
- mWakelock.release();
- }
- }
-
- String readHeaderLine(InputStream in) throws IOException {
- int c;
- StringBuilder buffer = new StringBuilder(80);
- while ((c = in.read()) >= 0) {
- if (c == '\n') break; // consume and discard the newlines
- buffer.append((char)c);
- }
- return buffer.toString();
- }
-
- InputStream attemptMasterKeyDecryption(String algorithm, byte[] userSalt, byte[] ckSalt,
- int rounds, String userIvHex, String masterKeyBlobHex, InputStream rawInStream,
- boolean doLog) {
- InputStream result = null;
-
- try {
- Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
- SecretKey userKey = buildPasswordKey(algorithm, mDecryptPassword, userSalt,
- rounds);
- byte[] IV = hexToByteArray(userIvHex);
- IvParameterSpec ivSpec = new IvParameterSpec(IV);
- c.init(Cipher.DECRYPT_MODE,
- new SecretKeySpec(userKey.getEncoded(), "AES"),
- ivSpec);
- byte[] mkCipher = hexToByteArray(masterKeyBlobHex);
- byte[] mkBlob = c.doFinal(mkCipher);
-
- // first, the master key IV
- int offset = 0;
- int len = mkBlob[offset++];
- IV = Arrays.copyOfRange(mkBlob, offset, offset + len);
- offset += len;
- // then the master key itself
- len = mkBlob[offset++];
- byte[] mk = Arrays.copyOfRange(mkBlob,
- offset, offset + len);
- offset += len;
- // and finally the master key checksum hash
- len = mkBlob[offset++];
- byte[] mkChecksum = Arrays.copyOfRange(mkBlob,
- offset, offset + len);
-
- // now validate the decrypted master key against the checksum
- byte[] calculatedCk = makeKeyChecksum(algorithm, mk, ckSalt, rounds);
- if (Arrays.equals(calculatedCk, mkChecksum)) {
- ivSpec = new IvParameterSpec(IV);
- c.init(Cipher.DECRYPT_MODE,
- new SecretKeySpec(mk, "AES"),
- ivSpec);
- // Only if all of the above worked properly will 'result' be assigned
- result = new CipherInputStream(rawInStream, c);
- } else if (doLog) Slog.w(TAG, "Incorrect password");
- } catch (InvalidAlgorithmParameterException e) {
- if (doLog) Slog.e(TAG, "Needed parameter spec unavailable!", e);
- } catch (BadPaddingException e) {
- // This case frequently occurs when the wrong password is used to decrypt
- // the master key. Use the identical "incorrect password" log text as is
- // used in the checksum failure log in order to avoid providing additional
- // information to an attacker.
- if (doLog) Slog.w(TAG, "Incorrect password");
- } catch (IllegalBlockSizeException e) {
- if (doLog) Slog.w(TAG, "Invalid block size in master key");
- } catch (NoSuchAlgorithmException e) {
- if (doLog) Slog.e(TAG, "Needed decryption algorithm unavailable!");
- } catch (NoSuchPaddingException e) {
- if (doLog) Slog.e(TAG, "Needed padding mechanism unavailable!");
- } catch (InvalidKeyException e) {
- if (doLog) Slog.w(TAG, "Illegal password; aborting");
- }
-
- return result;
- }
-
- InputStream decodeAesHeaderAndInitialize(String encryptionName, boolean pbkdf2Fallback,
- InputStream rawInStream) {
- InputStream result = null;
- try {
- if (encryptionName.equals(ENCRYPTION_ALGORITHM_NAME)) {
-
- String userSaltHex = readHeaderLine(rawInStream); // 5
- byte[] userSalt = hexToByteArray(userSaltHex);
-
- String ckSaltHex = readHeaderLine(rawInStream); // 6
- byte[] ckSalt = hexToByteArray(ckSaltHex);
-
- int rounds = Integer.parseInt(readHeaderLine(rawInStream)); // 7
- String userIvHex = readHeaderLine(rawInStream); // 8
-
- String masterKeyBlobHex = readHeaderLine(rawInStream); // 9
-
- // decrypt the master key blob
- result = attemptMasterKeyDecryption(PBKDF_CURRENT, userSalt, ckSalt,
- rounds, userIvHex, masterKeyBlobHex, rawInStream, false);
- if (result == null && pbkdf2Fallback) {
- result = attemptMasterKeyDecryption(PBKDF_FALLBACK, userSalt, ckSalt,
- rounds, userIvHex, masterKeyBlobHex, rawInStream, true);
- }
- } else Slog.w(TAG, "Unsupported encryption method: " + encryptionName);
- } catch (NumberFormatException e) {
- Slog.w(TAG, "Can't parse restore data header");
- } catch (IOException e) {
- Slog.w(TAG, "Can't read input header");
- }
-
- return result;
- }
-
- boolean restoreOneFile(InputStream instream, byte[] buffer) {
- FileMetadata info;
- try {
- info = readTarHeaders(instream);
- if (info != null) {
- if (MORE_DEBUG) {
- dumpFileMetadata(info);
- }
-
- final String pkg = info.packageName;
- if (!pkg.equals(mAgentPackage)) {
- // okay, change in package; set up our various
- // bookkeeping if we haven't seen it yet
- if (!mPackagePolicies.containsKey(pkg)) {
- mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
- }
-
- // Clean up the previous agent relationship if necessary,
- // and let the observer know we're considering a new app.
- if (mAgent != null) {
- if (DEBUG) Slog.d(TAG, "Saw new package; finalizing old one");
- // Now we're really done
- tearDownPipes();
- tearDownAgent(mTargetApp, true);
- mTargetApp = null;
- mAgentPackage = null;
- }
- }
-
- if (info.path.equals(BACKUP_MANIFEST_FILENAME)) {
- mPackagePolicies.put(pkg, readAppManifest(info, instream));
- mPackageInstallers.put(pkg, info.installerPackageName);
- // We've read only the manifest content itself at this point,
- // so consume the footer before looping around to the next
- // input file
- skipTarPadding(info.size, instream);
- sendOnRestorePackage(pkg);
- } else if (info.path.equals(BACKUP_METADATA_FILENAME)) {
- // Metadata blobs!
- readMetadata(info, instream);
- skipTarPadding(info.size, instream);
- } else {
- // Non-manifest, so it's actual file data. Is this a package
- // we're ignoring?
- boolean okay = true;
- RestorePolicy policy = mPackagePolicies.get(pkg);
- switch (policy) {
- case IGNORE:
- okay = false;
- break;
-
- case ACCEPT_IF_APK:
- // If we're in accept-if-apk state, then the first file we
- // see MUST be the apk.
- if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
- if (DEBUG) Slog.d(TAG, "APK file; installing");
- // Try to install the app.
- String installerName = mPackageInstallers.get(pkg);
- okay = installApk(info, installerName, instream);
- // good to go; promote to ACCEPT
- mPackagePolicies.put(pkg, (okay)
- ? RestorePolicy.ACCEPT
- : RestorePolicy.IGNORE);
- // At this point we've consumed this file entry
- // ourselves, so just strip the tar footer and
- // go on to the next file in the input stream
- skipTarPadding(info.size, instream);
- return true;
- } else {
- // File data before (or without) the apk. We can't
- // handle it coherently in this case so ignore it.
- mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
- okay = false;
- }
- break;
-
- case ACCEPT:
- if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
- if (DEBUG) Slog.d(TAG, "apk present but ACCEPT");
- // we can take the data without the apk, so we
- // *want* to do so. skip the apk by declaring this
- // one file not-okay without changing the restore
- // policy for the package.
- okay = false;
- }
- break;
-
- default:
- // Something has gone dreadfully wrong when determining
- // the restore policy from the manifest. Ignore the
- // rest of this package's data.
- Slog.e(TAG, "Invalid policy from manifest");
- okay = false;
- mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
- break;
- }
-
- // The path needs to be canonical
- if (info.path.contains("..") || info.path.contains("//")) {
- if (MORE_DEBUG) {
- Slog.w(TAG, "Dropping invalid path " + info.path);
- }
- okay = false;
- }
-
- // If the policy is satisfied, go ahead and set up to pipe the
- // data to the agent.
- if (DEBUG && okay && mAgent != null) {
- Slog.i(TAG, "Reusing existing agent instance");
- }
- if (okay && mAgent == null) {
- if (DEBUG) Slog.d(TAG, "Need to launch agent for " + pkg);
-
- try {
- mTargetApp = mPackageManager.getApplicationInfo(pkg, 0);
-
- // If we haven't sent any data to this app yet, we probably
- // need to clear it first. Check that.
- if (!mClearedPackages.contains(pkg)) {
- // apps with their own backup agents are
- // responsible for coherently managing a full
- // restore.
- if (mTargetApp.backupAgentName == null) {
- if (DEBUG) Slog.d(TAG, "Clearing app data preparatory to full restore");
- clearApplicationDataSynchronous(pkg);
- } else {
- if (DEBUG) Slog.d(TAG, "backup agent ("
- + mTargetApp.backupAgentName + ") => no clear");
- }
- mClearedPackages.add(pkg);
- } else {
- if (DEBUG) Slog.d(TAG, "We've initialized this app already; no clear required");
- }
-
- // All set; now set up the IPC and launch the agent
- setUpPipes();
- mAgent = bindToAgentSynchronous(mTargetApp,
- FullBackup.KEY_VALUE_DATA_TOKEN.equals(info.domain)
- ? ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL
- : ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL);
- mAgentPackage = pkg;
- } catch (IOException e) {
- // fall through to error handling
- } catch (NameNotFoundException e) {
- // fall through to error handling
- }
-
- if (mAgent == null) {
- if (DEBUG) Slog.d(TAG, "Unable to create agent for " + pkg);
- okay = false;
- tearDownPipes();
- mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
- }
- }
-
- // Sanity check: make sure we never give data to the wrong app. This
- // should never happen but a little paranoia here won't go amiss.
- if (okay && !pkg.equals(mAgentPackage)) {
- Slog.e(TAG, "Restoring data for " + pkg
- + " but agent is for " + mAgentPackage);
- okay = false;
- }
-
- // At this point we have an agent ready to handle the full
- // restore data as well as a pipe for sending data to
- // that agent. Tell the agent to start reading from the
- // pipe.
- if (okay) {
- boolean agentSuccess = true;
- long toCopy = info.size;
- final boolean isSharedStorage = pkg.equals(SHARED_BACKUP_AGENT_PACKAGE);
- final long timeout = isSharedStorage ?
- TIMEOUT_SHARED_BACKUP_INTERVAL : TIMEOUT_RESTORE_INTERVAL;
- final int token = generateRandomIntegerToken();
- try {
- prepareOperationTimeout(token, timeout, null,
- OP_TYPE_RESTORE_WAIT);
- if (FullBackup.OBB_TREE_TOKEN.equals(info.domain)) {
- if (DEBUG) Slog.d(TAG, "Restoring OBB file for " + pkg
- + " : " + info.path);
- mObbConnection.restoreObbFile(pkg, mPipes[0],
- info.size, info.type, info.path, info.mode,
- info.mtime, token, mBackupManagerBinder);
- } else if (FullBackup.KEY_VALUE_DATA_TOKEN.equals(info.domain)) {
- if (DEBUG) Slog.d(TAG, "Restoring key-value file for " + pkg
- + " : " + info.path);
- KeyValueAdbRestoreEngine restoreEngine =
- new KeyValueAdbRestoreEngine(BackupManagerService.this,
- mDataDir, info, mPipes[0], mAgent, token);
- new Thread(restoreEngine, "restore-key-value-runner").start();
- } else {
- if (DEBUG) Slog.d(TAG, "Invoking agent to restore file "
- + info.path);
- // fire up the app's agent listening on the socket. If
- // the agent is running in the system process we can't
- // just invoke it asynchronously, so we provide a thread
- // for it here.
- if (mTargetApp.processName.equals("system")) {
- Slog.d(TAG, "system process agent - spinning a thread");
- RestoreFileRunnable runner = new RestoreFileRunnable(
- mAgent, info, mPipes[0], token);
- new Thread(runner, "restore-sys-runner").start();
- } else {
- mAgent.doRestoreFile(mPipes[0], info.size, info.type,
- info.domain, info.path, info.mode, info.mtime,
- token, mBackupManagerBinder);
- }
- }
- } catch (IOException e) {
- // couldn't dup the socket for a process-local restore
- Slog.d(TAG, "Couldn't establish restore");
- agentSuccess = false;
- okay = false;
- } catch (RemoteException e) {
- // whoops, remote entity went away. We'll eat the content
- // ourselves, then, and not copy it over.
- Slog.e(TAG, "Agent crashed during full restore");
- agentSuccess = false;
- okay = false;
- }
-
- // Copy over the data if the agent is still good
- if (okay) {
- boolean pipeOkay = true;
- FileOutputStream pipe = new FileOutputStream(
- mPipes[1].getFileDescriptor());
- while (toCopy > 0) {
- int toRead = (toCopy > buffer.length)
- ? buffer.length : (int)toCopy;
- int nRead = instream.read(buffer, 0, toRead);
- if (nRead >= 0) mBytes += nRead;
- if (nRead <= 0) break;
- toCopy -= nRead;
-
- // send it to the output pipe as long as things
- // are still good
- if (pipeOkay) {
- try {
- pipe.write(buffer, 0, nRead);
- } catch (IOException e) {
- Slog.e(TAG, "Failed to write to restore pipe", e);
- pipeOkay = false;
- }
- }
- }
-
- // done sending that file! Now we just need to consume
- // the delta from info.size to the end of block.
- skipTarPadding(info.size, instream);
-
- // and now that we've sent it all, wait for the remote
- // side to acknowledge receipt
- agentSuccess = waitUntilOperationComplete(token);
- }
-
- // okay, if the remote end failed at any point, deal with
- // it by ignoring the rest of the restore on it
- if (!agentSuccess) {
- if (DEBUG) {
- Slog.d(TAG, "Agent failure restoring " + pkg + "; now ignoring");
- }
- mBackupHandler.removeMessages(MSG_RESTORE_OPERATION_TIMEOUT);
- tearDownPipes();
- tearDownAgent(mTargetApp, false);
- mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
- }
- }
-
- // Problems setting up the agent communication, or an already-
- // ignored package: skip to the next tar stream entry by
- // reading and discarding this file.
- if (!okay) {
- if (DEBUG) Slog.d(TAG, "[discarding file content]");
- long bytesToConsume = (info.size + 511) & ~511;
- while (bytesToConsume > 0) {
- int toRead = (bytesToConsume > buffer.length)
- ? buffer.length : (int)bytesToConsume;
- long nRead = instream.read(buffer, 0, toRead);
- if (nRead >= 0) mBytes += nRead;
- if (nRead <= 0) break;
- bytesToConsume -= nRead;
- }
- }
- }
- }
- } catch (IOException e) {
- if (DEBUG) Slog.w(TAG, "io exception on restore socket read", e);
- // treat as EOF
- info = null;
- }
-
- return (info != null);
- }
-
- void setUpPipes() throws IOException {
- mPipes = ParcelFileDescriptor.createPipe();
- }
-
- void tearDownPipes() {
- if (mPipes != null) {
- try {
- mPipes[0].close();
- mPipes[0] = null;
- mPipes[1].close();
- mPipes[1] = null;
- } catch (IOException e) {
- Slog.w(TAG, "Couldn't close agent pipes", e);
- }
- mPipes = null;
- }
- }
-
- void tearDownAgent(ApplicationInfo app, boolean doRestoreFinished) {
- if (mAgent != null) {
- try {
- // In the adb restore case, we do restore-finished here
- if (doRestoreFinished) {
- final int token = generateRandomIntegerToken();
- final AdbRestoreFinishedLatch latch = new AdbRestoreFinishedLatch(token);
- prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, latch,
- OP_TYPE_RESTORE_WAIT);
- if (mTargetApp.processName.equals("system")) {
- if (MORE_DEBUG) {
- Slog.d(TAG, "system agent - restoreFinished on thread");
- }
- Runnable runner = new RestoreFinishedRunnable(mAgent, token);
- new Thread(runner, "restore-sys-finished-runner").start();
- } else {
- mAgent.doRestoreFinished(token, mBackupManagerBinder);
- }
-
- latch.await();
- }
-
- // unbind and tidy up even on timeout or failure, just in case
- mActivityManager.unbindBackupAgent(app);
-
- // The agent was running with a stub Application object, so shut it down.
- // !!! We hardcode the confirmation UI's package name here rather than use a
- // manifest flag! TODO something less direct.
- if (app.uid >= Process.FIRST_APPLICATION_UID
- && !app.packageName.equals("com.android.backupconfirm")) {
- if (DEBUG) Slog.d(TAG, "Killing host process");
- mActivityManager.killApplicationProcess(app.processName, app.uid);
- } else {
- if (DEBUG) Slog.d(TAG, "Not killing after full restore");
- }
- } catch (RemoteException e) {
- Slog.d(TAG, "Lost app trying to shut down");
- }
- mAgent = null;
- }
- }
-
- class RestoreInstallObserver extends PackageInstallObserver {
- final AtomicBoolean mDone = new AtomicBoolean();
- String mPackageName;
- int mResult;
-
- public void reset() {
- synchronized (mDone) {
- mDone.set(false);
- }
- }
-
- public void waitForCompletion() {
- synchronized (mDone) {
- while (mDone.get() == false) {
- try {
- mDone.wait();
- } catch (InterruptedException e) { }
- }
- }
- }
-
- int getResult() {
- return mResult;
- }
-
- @Override
- public void onPackageInstalled(String packageName, int returnCode,
- String msg, Bundle extras) {
- synchronized (mDone) {
- mResult = returnCode;
- mPackageName = packageName;
- mDone.set(true);
- mDone.notifyAll();
- }
- }
- }
-
- class RestoreDeleteObserver extends IPackageDeleteObserver.Stub {
- final AtomicBoolean mDone = new AtomicBoolean();
- int mResult;
-
- public void reset() {
- synchronized (mDone) {
- mDone.set(false);
- }
- }
-
- public void waitForCompletion() {
- synchronized (mDone) {
- while (mDone.get() == false) {
- try {
- mDone.wait();
- } catch (InterruptedException e) { }
- }
- }
- }
-
- @Override
- public void packageDeleted(String packageName, int returnCode) throws RemoteException {
- synchronized (mDone) {
- mResult = returnCode;
- mDone.set(true);
- mDone.notifyAll();
- }
- }
- }
-
- final RestoreInstallObserver mInstallObserver = new RestoreInstallObserver();
- final RestoreDeleteObserver mDeleteObserver = new RestoreDeleteObserver();
-
- boolean installApk(FileMetadata info, String installerPackage, InputStream instream) {
- boolean okay = true;
-
- if (DEBUG) Slog.d(TAG, "Installing from backup: " + info.packageName);
-
- // The file content is an .apk file. Copy it out to a staging location and
- // attempt to install it.
- File apkFile = new File(mDataDir, info.packageName);
- try {
- FileOutputStream apkStream = new FileOutputStream(apkFile);
- byte[] buffer = new byte[32 * 1024];
- long size = info.size;
- while (size > 0) {
- long toRead = (buffer.length < size) ? buffer.length : size;
- int didRead = instream.read(buffer, 0, (int)toRead);
- if (didRead >= 0) mBytes += didRead;
- apkStream.write(buffer, 0, didRead);
- size -= didRead;
- }
- apkStream.close();
-
- // make sure the installer can read it
- apkFile.setReadable(true, false);
-
- // Now install it
- Uri packageUri = Uri.fromFile(apkFile);
- mInstallObserver.reset();
- mPackageManager.installPackage(packageUri, mInstallObserver,
- PackageManager.INSTALL_REPLACE_EXISTING | PackageManager.INSTALL_FROM_ADB,
- installerPackage);
- mInstallObserver.waitForCompletion();
-
- if (mInstallObserver.getResult() != PackageManager.INSTALL_SUCCEEDED) {
- // The only time we continue to accept install of data even if the
- // apk install failed is if we had already determined that we could
- // accept the data regardless.
- if (mPackagePolicies.get(info.packageName) != RestorePolicy.ACCEPT) {
- okay = false;
- }
- } else {
- // Okay, the install succeeded. Make sure it was the right app.
- boolean uninstall = false;
- if (!mInstallObserver.mPackageName.equals(info.packageName)) {
- Slog.w(TAG, "Restore stream claimed to include apk for "
- + info.packageName + " but apk was really "
- + mInstallObserver.mPackageName);
- // delete the package we just put in place; it might be fraudulent
- okay = false;
- uninstall = true;
- } else {
- try {
- PackageInfo pkg = mPackageManager.getPackageInfo(info.packageName,
- PackageManager.GET_SIGNATURES);
- if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
- Slog.w(TAG, "Restore stream contains apk of package "
- + info.packageName + " but it disallows backup/restore");
- okay = false;
- } else {
- // So far so good -- do the signatures match the manifest?
- Signature[] sigs = mManifestSignatures.get(info.packageName);
- if (signaturesMatch(sigs, pkg)) {
- // If this is a system-uid app without a declared backup agent,
- // don't restore any of the file data.
- if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
- && (pkg.applicationInfo.backupAgentName == null)) {
- Slog.w(TAG, "Installed app " + info.packageName
- + " has restricted uid and no agent");
- okay = false;
- }
- } else {
- Slog.w(TAG, "Installed app " + info.packageName
- + " signatures do not match restore manifest");
- okay = false;
- uninstall = true;
- }
- }
- } catch (NameNotFoundException e) {
- Slog.w(TAG, "Install of package " + info.packageName
- + " succeeded but now not found");
- okay = false;
- }
- }
-
- // If we're not okay at this point, we need to delete the package
- // that we just installed.
- if (uninstall) {
- mDeleteObserver.reset();
- mPackageManager.deletePackage(mInstallObserver.mPackageName,
- mDeleteObserver, 0);
- mDeleteObserver.waitForCompletion();
- }
- }
- } catch (IOException e) {
- Slog.e(TAG, "Unable to transcribe restored apk for install");
- okay = false;
- } finally {
- apkFile.delete();
- }
-
- return okay;
- }
-
- // Given an actual file content size, consume the post-content padding mandated
- // by the tar format.
- void skipTarPadding(long size, InputStream instream) throws IOException {
- long partial = (size + 512) % 512;
- if (partial > 0) {
- final int needed = 512 - (int)partial;
- byte[] buffer = new byte[needed];
- if (readExactly(instream, buffer, 0, needed) == needed) {
- mBytes += needed;
- } else throw new IOException("Unexpected EOF in padding");
- }
- }
-
- // Read a widget metadata file, returning the restored blob
- void readMetadata(FileMetadata info, InputStream instream) throws IOException {
- // Fail on suspiciously large widget dump files
- if (info.size > 64 * 1024) {
- throw new IOException("Metadata too big; corrupt? size=" + info.size);
- }
-
- byte[] buffer = new byte[(int) info.size];
- if (readExactly(instream, buffer, 0, (int)info.size) == info.size) {
- mBytes += info.size;
- } else throw new IOException("Unexpected EOF in widget data");
-
- String[] str = new String[1];
- int offset = extractLine(buffer, 0, str);
- int version = Integer.parseInt(str[0]);
- if (version == BACKUP_MANIFEST_VERSION) {
- offset = extractLine(buffer, offset, str);
- final String pkg = str[0];
- if (info.packageName.equals(pkg)) {
- // Data checks out -- the rest of the buffer is a concatenation of
- // binary blobs as described in the comment at writeAppWidgetData()
- ByteArrayInputStream bin = new ByteArrayInputStream(buffer,
- offset, buffer.length - offset);
- DataInputStream in = new DataInputStream(bin);
- while (bin.available() > 0) {
- int token = in.readInt();
- int size = in.readInt();
- if (size > 64 * 1024) {
- throw new IOException("Datum "
- + Integer.toHexString(token)
- + " too big; corrupt? size=" + info.size);
- }
- switch (token) {
- case BACKUP_WIDGET_METADATA_TOKEN:
- {
- if (MORE_DEBUG) {
- Slog.i(TAG, "Got widget metadata for " + info.packageName);
- }
- mWidgetData = new byte[size];
- in.read(mWidgetData);
- break;
- }
- default:
- {
- if (DEBUG) {
- Slog.i(TAG, "Ignoring metadata blob "
- + Integer.toHexString(token)
- + " for " + info.packageName);
- }
- in.skipBytes(size);
- break;
- }
- }
- }
- } else {
- Slog.w(TAG, "Metadata mismatch: package " + info.packageName
- + " but widget data for " + pkg);
- }
- } else {
- Slog.w(TAG, "Unsupported metadata version " + version);
- }
- }
-
- // Returns a policy constant; takes a buffer arg to reduce memory churn
- RestorePolicy readAppManifest(FileMetadata info, InputStream instream)
- throws IOException {
- // Fail on suspiciously large manifest files
- if (info.size > 64 * 1024) {
- throw new IOException("Restore manifest too big; corrupt? size=" + info.size);
- }
-
- byte[] buffer = new byte[(int) info.size];
- if (readExactly(instream, buffer, 0, (int)info.size) == info.size) {
- mBytes += info.size;
- } else throw new IOException("Unexpected EOF in manifest");
-
- RestorePolicy policy = RestorePolicy.IGNORE;
- String[] str = new String[1];
- int offset = 0;
-
- try {
- offset = extractLine(buffer, offset, str);
- int version = Integer.parseInt(str[0]);
- if (version == BACKUP_MANIFEST_VERSION) {
- offset = extractLine(buffer, offset, str);
- String manifestPackage = str[0];
- // TODO: handle <original-package>
- if (manifestPackage.equals(info.packageName)) {
- offset = extractLine(buffer, offset, str);
- version = Integer.parseInt(str[0]); // app version
- offset = extractLine(buffer, offset, str);
- // This is the platform version, which we don't use, but we parse it
- // as a safety against corruption in the manifest.
- Integer.parseInt(str[0]);
- offset = extractLine(buffer, offset, str);
- info.installerPackageName = (str[0].length() > 0) ? str[0] : null;
- offset = extractLine(buffer, offset, str);
- boolean hasApk = str[0].equals("1");
- offset = extractLine(buffer, offset, str);
- int numSigs = Integer.parseInt(str[0]);
- if (numSigs > 0) {
- Signature[] sigs = new Signature[numSigs];
- for (int i = 0; i < numSigs; i++) {
- offset = extractLine(buffer, offset, str);
- sigs[i] = new Signature(str[0]);
- }
- mManifestSignatures.put(info.packageName, sigs);
-
- // Okay, got the manifest info we need...
- try {
- PackageInfo pkgInfo = mPackageManager.getPackageInfo(
- info.packageName, PackageManager.GET_SIGNATURES);
- // Fall through to IGNORE if the app explicitly disallows backup
- final int flags = pkgInfo.applicationInfo.flags;
- if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
- // Restore system-uid-space packages only if they have
- // defined a custom backup agent
- if ((pkgInfo.applicationInfo.uid >= Process.FIRST_APPLICATION_UID)
- || (pkgInfo.applicationInfo.backupAgentName != null)) {
- // Verify signatures against any installed version; if they
- // don't match, then we fall though and ignore the data. The
- // signatureMatch() method explicitly ignores the signature
- // check for packages installed on the system partition, because
- // such packages are signed with the platform cert instead of
- // the app developer's cert, so they're different on every
- // device.
- if (signaturesMatch(sigs, pkgInfo)) {
- if ((pkgInfo.applicationInfo.flags
- & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
- Slog.i(TAG, "Package has restoreAnyVersion; taking data");
- policy = RestorePolicy.ACCEPT;
- } else if (pkgInfo.versionCode >= version) {
- Slog.i(TAG, "Sig + version match; taking data");
- policy = RestorePolicy.ACCEPT;
- } else {
- // The data is from a newer version of the app than
- // is presently installed. That means we can only
- // use it if the matching apk is also supplied.
- Slog.d(TAG, "Data version " + version
- + " is newer than installed version "
- + pkgInfo.versionCode + " - requiring apk");
- policy = RestorePolicy.ACCEPT_IF_APK;
- }
- } else {
- Slog.w(TAG, "Restore manifest signatures do not match "
- + "installed application for " + info.packageName);
- }
- } else {
- Slog.w(TAG, "Package " + info.packageName
- + " is system level with no agent");
- }
- } else {
- if (DEBUG) Slog.i(TAG, "Restore manifest from "
- + info.packageName + " but allowBackup=false");
- }
- } catch (NameNotFoundException e) {
- // Okay, the target app isn't installed. We can process
- // the restore properly only if the dataset provides the
- // apk file and we can successfully install it.
- if (DEBUG) Slog.i(TAG, "Package " + info.packageName
- + " not installed; requiring apk in dataset");
- policy = RestorePolicy.ACCEPT_IF_APK;
- }
-
- if (policy == RestorePolicy.ACCEPT_IF_APK && !hasApk) {
- Slog.i(TAG, "Cannot restore package " + info.packageName
- + " without the matching .apk");
- }
- } else {
- Slog.i(TAG, "Missing signature on backed-up package "
- + info.packageName);
- }
- } else {
- Slog.i(TAG, "Expected package " + info.packageName
- + " but restore manifest claims " + manifestPackage);
- }
- } else {
- Slog.i(TAG, "Unknown restore manifest version " + version
- + " for package " + info.packageName);
- }
- } catch (NumberFormatException e) {
- Slog.w(TAG, "Corrupt restore manifest for package " + info.packageName);
- } catch (IllegalArgumentException e) {
- Slog.w(TAG, e.getMessage());
- }
-
- return policy;
- }
-
- // Builds a line from a byte buffer starting at 'offset', and returns
- // the index of the next unconsumed data in the buffer.
- int extractLine(byte[] buffer, int offset, String[] outStr) throws IOException {
- final int end = buffer.length;
- if (offset >= end) throw new IOException("Incomplete data");
-
- int pos;
- for (pos = offset; pos < end; pos++) {
- byte c = buffer[pos];
- // at LF we declare end of line, and return the next char as the
- // starting point for the next time through
- if (c == '\n') {
- break;
- }
- }
- outStr[0] = new String(buffer, offset, pos - offset);
- pos++; // may be pointing an extra byte past the end but that's okay
- return pos;
- }
-
- void dumpFileMetadata(FileMetadata info) {
- if (DEBUG) {
- StringBuilder b = new StringBuilder(128);
-
- // mode string
- b.append((info.type == BackupAgent.TYPE_DIRECTORY) ? 'd' : '-');
- b.append(((info.mode & 0400) != 0) ? 'r' : '-');
- b.append(((info.mode & 0200) != 0) ? 'w' : '-');
- b.append(((info.mode & 0100) != 0) ? 'x' : '-');
- b.append(((info.mode & 0040) != 0) ? 'r' : '-');
- b.append(((info.mode & 0020) != 0) ? 'w' : '-');
- b.append(((info.mode & 0010) != 0) ? 'x' : '-');
- b.append(((info.mode & 0004) != 0) ? 'r' : '-');
- b.append(((info.mode & 0002) != 0) ? 'w' : '-');
- b.append(((info.mode & 0001) != 0) ? 'x' : '-');
- b.append(String.format(" %9d ", info.size));
-
- Date stamp = new Date(info.mtime);
- b.append(new SimpleDateFormat("MMM dd HH:mm:ss ").format(stamp));
-
- b.append(info.packageName);
- b.append(" :: ");
- b.append(info.domain);
- b.append(" :: ");
- b.append(info.path);
-
- Slog.i(TAG, b.toString());
- }
- }
-
- // Consume a tar file header block [sequence] and accumulate the relevant metadata
- FileMetadata readTarHeaders(InputStream instream) throws IOException {
- byte[] block = new byte[512];
- FileMetadata info = null;
-
- boolean gotHeader = readTarHeader(instream, block);
- if (gotHeader) {
- try {
- // okay, presume we're okay, and extract the various metadata
- info = new FileMetadata();
- info.size = extractRadix(block, 124, 12, 8);
- info.mtime = extractRadix(block, 136, 12, 8);
- info.mode = extractRadix(block, 100, 8, 8);
-
- info.path = extractString(block, 345, 155); // prefix
- String path = extractString(block, 0, 100);
- if (path.length() > 0) {
- if (info.path.length() > 0) info.path += '/';
- info.path += path;
- }
-
- // tar link indicator field: 1 byte at offset 156 in the header.
- int typeChar = block[156];
- if (typeChar == 'x') {
- // pax extended header, so we need to read that
- gotHeader = readPaxExtendedHeader(instream, info);
- if (gotHeader) {
- // and after a pax extended header comes another real header -- read
- // that to find the real file type
- gotHeader = readTarHeader(instream, block);
- }
- if (!gotHeader) throw new IOException("Bad or missing pax header");
-
- typeChar = block[156];
- }
-
- switch (typeChar) {
- case '0': info.type = BackupAgent.TYPE_FILE; break;
- case '5': {
- info.type = BackupAgent.TYPE_DIRECTORY;
- if (info.size != 0) {
- Slog.w(TAG, "Directory entry with nonzero size in header");
- info.size = 0;
- }
- break;
- }
- case 0: {
- // presume EOF
- if (DEBUG) Slog.w(TAG, "Saw type=0 in tar header block, info=" + info);
- return null;
- }
- default: {
- Slog.e(TAG, "Unknown tar entity type: " + typeChar);
- throw new IOException("Unknown entity type " + typeChar);
- }
- }
-
- // Parse out the path
- //
- // first: apps/shared/unrecognized
- if (FullBackup.SHARED_PREFIX.regionMatches(0,
- info.path, 0, FullBackup.SHARED_PREFIX.length())) {
- // File in shared storage. !!! TODO: implement this.
- info.path = info.path.substring(FullBackup.SHARED_PREFIX.length());
- info.packageName = SHARED_BACKUP_AGENT_PACKAGE;
- info.domain = FullBackup.SHARED_STORAGE_TOKEN;
- if (DEBUG) Slog.i(TAG, "File in shared storage: " + info.path);
- } else if (FullBackup.APPS_PREFIX.regionMatches(0,
- info.path, 0, FullBackup.APPS_PREFIX.length())) {
- // App content! Parse out the package name and domain
-
- // strip the apps/ prefix
- info.path = info.path.substring(FullBackup.APPS_PREFIX.length());
-
- // extract the package name
- int slash = info.path.indexOf('/');
- if (slash < 0) throw new IOException("Illegal semantic path in " + info.path);
- info.packageName = info.path.substring(0, slash);
- info.path = info.path.substring(slash+1);
-
- // if it's a manifest or metadata payload we're done, otherwise parse
- // out the domain into which the file will be restored
- if (!info.path.equals(BACKUP_MANIFEST_FILENAME)
- && !info.path.equals(BACKUP_METADATA_FILENAME)) {
- slash = info.path.indexOf('/');
- if (slash < 0) throw new IOException("Illegal semantic path in non-manifest " + info.path);
- info.domain = info.path.substring(0, slash);
- info.path = info.path.substring(slash + 1);
- }
- }
- } catch (IOException e) {
- if (DEBUG) {
- Slog.e(TAG, "Parse error in header: " + e.getMessage());
- HEXLOG(block);
- }
- throw e;
- }
- }
- return info;
- }
-
- private void HEXLOG(byte[] block) {
- int offset = 0;
- int todo = block.length;
- StringBuilder buf = new StringBuilder(64);
- while (todo > 0) {
- buf.append(String.format("%04x ", offset));
- int numThisLine = (todo > 16) ? 16 : todo;
- for (int i = 0; i < numThisLine; i++) {
- buf.append(String.format("%02x ", block[offset+i]));
- }
- Slog.i("hexdump", buf.toString());
- buf.setLength(0);
- todo -= numThisLine;
- offset += numThisLine;
- }
- }
-
- // Read exactly the given number of bytes into a buffer at the stated offset.
- // Returns false if EOF is encountered before the requested number of bytes
- // could be read.
- int readExactly(InputStream in, byte[] buffer, int offset, int size)
- throws IOException {
- if (size <= 0) throw new IllegalArgumentException("size must be > 0");
-
- int soFar = 0;
- while (soFar < size) {
- int nRead = in.read(buffer, offset + soFar, size - soFar);
- if (nRead <= 0) {
- if (MORE_DEBUG) Slog.w(TAG, "- wanted exactly " + size + " but got only " + soFar);
- break;
- }
- soFar += nRead;
- }
- return soFar;
- }
-
- boolean readTarHeader(InputStream instream, byte[] block) throws IOException {
- final int got = readExactly(instream, block, 0, 512);
- if (got == 0) return false; // Clean EOF
- if (got < 512) throw new IOException("Unable to read full block header");
- mBytes += 512;
- return true;
- }
-
- // overwrites 'info' fields based on the pax extended header
- boolean readPaxExtendedHeader(InputStream instream, FileMetadata info)
- throws IOException {
- // We should never see a pax extended header larger than this
- if (info.size > 32*1024) {
- Slog.w(TAG, "Suspiciously large pax header size " + info.size
- + " - aborting");
- throw new IOException("Sanity failure: pax header size " + info.size);
- }
-
- // read whole blocks, not just the content size
- int numBlocks = (int)((info.size + 511) >> 9);
- byte[] data = new byte[numBlocks * 512];
- if (readExactly(instream, data, 0, data.length) < data.length) {
- throw new IOException("Unable to read full pax header");
- }
- mBytes += data.length;
-
- final int contentSize = (int) info.size;
- int offset = 0;
- do {
- // extract the line at 'offset'
- int eol = offset+1;
- while (eol < contentSize && data[eol] != ' ') eol++;
- if (eol >= contentSize) {
- // error: we just hit EOD looking for the end of the size field
- throw new IOException("Invalid pax data");
- }
- // eol points to the space between the count and the key
- int linelen = (int) extractRadix(data, offset, eol - offset, 10);
- int key = eol + 1; // start of key=value
- eol = offset + linelen - 1; // trailing LF
- int value;
- for (value = key+1; data[value] != '=' && value <= eol; value++);
- if (value > eol) {
- throw new IOException("Invalid pax declaration");
- }
-
- // pax requires that key/value strings be in UTF-8
- String keyStr = new String(data, key, value-key, "UTF-8");
- // -1 to strip the trailing LF
- String valStr = new String(data, value+1, eol-value-1, "UTF-8");
-
- if ("path".equals(keyStr)) {
- info.path = valStr;
- } else if ("size".equals(keyStr)) {
- info.size = Long.parseLong(valStr);
- } else {
- if (DEBUG) Slog.i(TAG, "Unhandled pax key: " + key);
- }
-
- offset += linelen;
- } while (offset < contentSize);
-
- return true;
- }
-
- long extractRadix(byte[] data, int offset, int maxChars, int radix)
- throws IOException {
- long value = 0;
- final int end = offset + maxChars;
- for (int i = offset; i < end; i++) {
- final byte b = data[i];
- // Numeric fields in tar can terminate with either NUL or SPC
- if (b == 0 || b == ' ') break;
- if (b < '0' || b > ('0' + radix - 1)) {
- throw new IOException("Invalid number in header: '" + (char)b + "' for radix " + radix);
- }
- value = radix * value + (b - '0');
- }
- return value;
- }
-
- String extractString(byte[] data, int offset, int maxChars) throws IOException {
- final int end = offset + maxChars;
- int eos = offset;
- // tar string fields terminate early with a NUL
- while (eos < end && data[eos] != 0) eos++;
- return new String(data, offset, eos-offset, "US-ASCII");
- }
-
- void sendStartRestore() {
- if (mObserver != null) {
- try {
- mObserver.onStartRestore();
- } catch (RemoteException e) {
- Slog.w(TAG, "full restore observer went away: startRestore");
- mObserver = null;
- }
- }
- }
-
- void sendOnRestorePackage(String name) {
- if (mObserver != null) {
- try {
- // TODO: use a more user-friendly name string
- mObserver.onRestorePackage(name);
- } catch (RemoteException e) {
- Slog.w(TAG, "full restore observer went away: restorePackage");
- mObserver = null;
- }
- }
- }
-
- void sendEndRestore() {
- if (mObserver != null) {
- try {
- mObserver.onEndRestore();
- } catch (RemoteException e) {
- Slog.w(TAG, "full restore observer went away: endRestore");
- mObserver = null;
- }
- }
- }
- }
-
- // ----- Restore handling -----
-
- /**
- * Returns whether the signatures stored {@param storedSigs}, coming from the source apk, match
- * the signatures of the apk installed on the device, the target apk. If the target resides in
- * the system partition we return true. Otherwise it's considered a match if both conditions
- * hold:
- *
- * <ul>
- * <li>Source and target have at least one signature each
- * <li>Target contains all signatures in source
- * </ul>
- *
- * Note that if {@param target} is null we return false.
- */
- static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) {
- if (target == null) {
- return false;
- }
-
- // If the target resides on the system partition, we allow it to restore
- // data from the like-named package in a restore set even if the signatures
- // do not match. (Unlike general applications, those flashed to the system
- // partition will be signed with the device's platform certificate, so on
- // different phones the same system app will have different signatures.)
- if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- if (MORE_DEBUG) {
- Slog.v(TAG, "System app " + target.packageName + " - skipping sig check");
- }
- return true;
- }
-
- Signature[] deviceSigs = target.signatures;
- if (MORE_DEBUG) {
- Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs + " device=" + deviceSigs);
- }
-
- // Don't allow unsigned apps on either end
- if (ArrayUtils.isEmpty(storedSigs) || ArrayUtils.isEmpty(deviceSigs)) {
- return false;
- }
-
- // Signatures can be added over time, so the target-device apk needs to contain all the
- // source-device apk signatures, but not necessarily the other way around.
- int nStored = storedSigs.length;
- int nDevice = deviceSigs.length;
-
- for (int i=0; i < nStored; i++) {
- boolean match = false;
- for (int j=0; j < nDevice; j++) {
- if (storedSigs[i].equals(deviceSigs[j])) {
- match = true;
- break;
- }
- }
- if (!match) {
- return false;
- }
- }
- return true;
- }
-
- // Used by both incremental and full restore
- void restoreWidgetData(String packageName, byte[] widgetData) {
- // Apply the restored widget state and generate the ID update for the app
- // TODO: http://b/22388012
- if (MORE_DEBUG) {
- Slog.i(TAG, "Incorporating restored widget data");
- }
- AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, UserHandle.USER_SYSTEM);
- }
-
- // *****************************
- // NEW UNIFIED RESTORE IMPLEMENTATION
- // *****************************
-
- // states of the unified-restore state machine
- enum UnifiedRestoreState {
- INITIAL,
- RUNNING_QUEUE,
- RESTORE_KEYVALUE,
- RESTORE_FULL,
- RESTORE_FINISHED,
- FINAL
- }
-
- class PerformUnifiedRestoreTask implements BackupRestoreTask {
- // Transport we're working with to do the restore
- private IBackupTransport mTransport;
-
- // Where per-transport saved state goes
- File mStateDir;
-
- // Restore observer; may be null
- private IRestoreObserver mObserver;
-
- // BackuoManagerMonitor; may be null
- private IBackupManagerMonitor mMonitor;
-
- // Token identifying the dataset to the transport
- private long mToken;
-
- // When this is a restore-during-install, this is the token identifying the
- // operation to the Package Manager, and we must ensure that we let it know
- // when we're finished.
- private int mPmToken;
-
- // When this is restore-during-install, we need to tell the package manager
- // whether we actually launched the app, because this affects notifications
- // around externally-visible state transitions.
- private boolean mDidLaunch;
-
- // Is this a whole-system restore, i.e. are we establishing a new ancestral
- // dataset to base future restore-at-install operations from?
- private boolean mIsSystemRestore;
-
- // If this is a single-package restore, what package are we interested in?
- private PackageInfo mTargetPackage;
-
- // In all cases, the calculated list of packages that we are trying to restore
- private List<PackageInfo> mAcceptSet;
-
- // Our bookkeeping about the ancestral dataset
- private PackageManagerBackupAgent mPmAgent;
-
- // Currently-bound backup agent for restore + restoreFinished purposes
- private IBackupAgent mAgent;
-
- // What sort of restore we're doing now
- private RestoreDescription mRestoreDescription;
-
- // The package we're currently restoring
- private PackageInfo mCurrentPackage;
-
- // Widget-related data handled as part of this restore operation
- private byte[] mWidgetData;
-
- // Number of apps restored in this pass
- private int mCount;
-
- // When did we start?
- private long mStartRealtime;
-
- // State machine progress
- private UnifiedRestoreState mState;
-
- // How are things going?
- private int mStatus;
-
- // Done?
- private boolean mFinished;
-
- // Key/value: bookkeeping about staged data and files for agent access
- private File mBackupDataName;
- private File mStageName;
- private File mSavedStateName;
- private File mNewStateName;
- ParcelFileDescriptor mBackupData;
- ParcelFileDescriptor mNewState;
-
- private final int mEphemeralOpToken;
-
- // Invariant: mWakelock is already held, and this task is responsible for
- // releasing it at the end of the restore operation.
- PerformUnifiedRestoreTask(IBackupTransport transport, IRestoreObserver observer,
- IBackupManagerMonitor monitor, long restoreSetToken, PackageInfo targetPackage,
- int pmToken, boolean isFullSystemRestore, String[] filterSet) {
- mEphemeralOpToken = generateRandomIntegerToken();
- mState = UnifiedRestoreState.INITIAL;
- mStartRealtime = SystemClock.elapsedRealtime();
-
- mTransport = transport;
- mObserver = observer;
- mMonitor = monitor;
- mToken = restoreSetToken;
- mPmToken = pmToken;
- mTargetPackage = targetPackage;
- mIsSystemRestore = isFullSystemRestore;
- mFinished = false;
- mDidLaunch = false;
-
- if (targetPackage != null) {
- // Single package restore
- mAcceptSet = new ArrayList<PackageInfo>();
- mAcceptSet.add(targetPackage);
- } else {
- // Everything possible, or a target set
- if (filterSet == null) {
- // We want everything and a pony
- List<PackageInfo> apps =
- PackageManagerBackupAgent.getStorableApplications(mPackageManager);
- filterSet = packagesToNames(apps);
- if (DEBUG) {
- Slog.i(TAG, "Full restore; asking about " + filterSet.length + " apps");
- }
- }
-
- mAcceptSet = new ArrayList<PackageInfo>(filterSet.length);
-
- // Pro tem, we insist on moving the settings provider package to last place.
- // Keep track of whether it's in the list, and bump it down if so. We also
- // want to do the system package itself first if it's called for.
- boolean hasSystem = false;
- boolean hasSettings = false;
- for (int i = 0; i < filterSet.length; i++) {
- try {
- PackageInfo info = mPackageManager.getPackageInfo(filterSet[i], 0);
- if ("android".equals(info.packageName)) {
- hasSystem = true;
- continue;
- }
- if (SETTINGS_PACKAGE.equals(info.packageName)) {
- hasSettings = true;
- continue;
- }
-
- if (appIsEligibleForBackup(info.applicationInfo, mPackageManager)) {
- mAcceptSet.add(info);
- }
- } catch (NameNotFoundException e) {
- // requested package name doesn't exist; ignore it
- }
- }
- if (hasSystem) {
- try {
- mAcceptSet.add(0, mPackageManager.getPackageInfo("android", 0));
- } catch (NameNotFoundException e) {
- // won't happen; we know a priori that it's valid
- }
- }
- if (hasSettings) {
- try {
- mAcceptSet.add(mPackageManager.getPackageInfo(SETTINGS_PACKAGE, 0));
- } catch (NameNotFoundException e) {
- // this one is always valid too
- }
- }
- }
-
- if (MORE_DEBUG) {
- Slog.v(TAG, "Restore; accept set size is " + mAcceptSet.size());
- for (PackageInfo info : mAcceptSet) {
- Slog.v(TAG, " " + info.packageName);
- }
- }
- }
-
- private String[] packagesToNames(List<PackageInfo> apps) {
- final int N = apps.size();
- String[] names = new String[N];
- for (int i = 0; i < N; i++) {
- names[i] = apps.get(i).packageName;
- }
- return names;
- }
-
- // Execute one tick of whatever state machine the task implements
- @Override
- public void execute() {
- if (MORE_DEBUG) Slog.v(TAG, "*** Executing restore step " + mState);
- switch (mState) {
- case INITIAL:
- startRestore();
- break;
-
- case RUNNING_QUEUE:
- dispatchNextRestore();
- break;
-
- case RESTORE_KEYVALUE:
- restoreKeyValue();
- break;
-
- case RESTORE_FULL:
- restoreFull();
- break;
-
- case RESTORE_FINISHED:
- restoreFinished();
- break;
-
- case FINAL:
- if (!mFinished) finalizeRestore();
- else {
- Slog.e(TAG, "Duplicate finish");
- }
- mFinished = true;
- break;
- }
- }
-
- /*
- * SKETCH OF OPERATION
- *
- * create one of these PerformUnifiedRestoreTask objects, telling it which
- * dataset & transport to address, and then parameters within the restore
- * operation: single target package vs many, etc.
- *
- * 1. transport.startRestore(token, list-of-packages). If we need @pm@ it is
- * always placed first and the settings provider always placed last [for now].
- *
- * 1a [if we needed @pm@ then nextRestorePackage() and restore the PMBA inline]
- *
- * [ state change => RUNNING_QUEUE ]
- *
- * NOW ITERATE:
- *
- * { 3. t.nextRestorePackage()
- * 4. does the metadata for this package allow us to restore it?
- * does the on-disk app permit us to restore it? [re-check allowBackup etc]
- * 5. is this a key/value dataset? => key/value agent restore
- * [ state change => RESTORE_KEYVALUE ]
- * 5a. spin up agent
- * 5b. t.getRestoreData() to stage it properly
- * 5c. call into agent to perform restore
- * 5d. tear down agent
- * [ state change => RUNNING_QUEUE ]
- *
- * 6. else it's a stream dataset:
- * [ state change => RESTORE_FULL ]
- * 6a. instantiate the engine for a stream restore: engine handles agent lifecycles
- * 6b. spin off engine runner on separate thread
- * 6c. ITERATE getNextFullRestoreDataChunk() and copy data to engine runner socket
- * [ state change => RUNNING_QUEUE ]
- * }
- *
- * [ state change => FINAL ]
- *
- * 7. t.finishRestore(), release wakelock, etc.
- *
- *
- */
-
- // state INITIAL : set up for the restore and read the metadata if necessary
- private void startRestore() {
- sendStartRestore(mAcceptSet.size());
-
- // If we're starting a full-system restore, set up to begin widget ID remapping
- if (mIsSystemRestore) {
- // TODO: http://b/22388012
- AppWidgetBackupBridge.restoreStarting(UserHandle.USER_SYSTEM);
- }
-
- try {
- String transportDir = mTransport.transportDirName();
- mStateDir = new File(mBaseStateDir, transportDir);
-
- // Fetch the current metadata from the dataset first
- PackageInfo pmPackage = new PackageInfo();
- pmPackage.packageName = PACKAGE_MANAGER_SENTINEL;
- mAcceptSet.add(0, pmPackage);
-
- PackageInfo[] packages = mAcceptSet.toArray(new PackageInfo[0]);
- mStatus = mTransport.startRestore(mToken, packages);
- if (mStatus != BackupTransport.TRANSPORT_OK) {
- Slog.e(TAG, "Transport error " + mStatus + "; no restore possible");
- mStatus = BackupTransport.TRANSPORT_ERROR;
- executeNextState(UnifiedRestoreState.FINAL);
- return;
- }
-
- RestoreDescription desc = mTransport.nextRestorePackage();
- if (desc == null) {
- Slog.e(TAG, "No restore metadata available; halting");
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_NO_RESTORE_METADATA_AVAILABLE,
- mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
- mStatus = BackupTransport.TRANSPORT_ERROR;
- executeNextState(UnifiedRestoreState.FINAL);
- return;
- }
- if (!PACKAGE_MANAGER_SENTINEL.equals(desc.getPackageName())) {
- Slog.e(TAG, "Required package metadata but got "
- + desc.getPackageName());
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_NO_PM_METADATA_RECEIVED,
- mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
- mStatus = BackupTransport.TRANSPORT_ERROR;
- executeNextState(UnifiedRestoreState.FINAL);
- return;
- }
-
- // Pull the Package Manager metadata from the restore set first
- mCurrentPackage = new PackageInfo();
- mCurrentPackage.packageName = PACKAGE_MANAGER_SENTINEL;
- mPmAgent = makeMetadataAgent(null);
- mAgent = IBackupAgent.Stub.asInterface(mPmAgent.onBind());
- if (MORE_DEBUG) {
- Slog.v(TAG, "initiating restore for PMBA");
- }
- initiateOneRestore(mCurrentPackage, 0);
- // The PM agent called operationComplete() already, because our invocation
- // of it is process-local and therefore synchronous. That means that the
- // next-state message (RUNNING_QUEUE) is already enqueued. Only if we're
- // unable to proceed with running the queue do we remove that pending
- // message and jump straight to the FINAL state. Because this was
- // synchronous we also know that we should cancel the pending timeout
- // message.
- mBackupHandler.removeMessages(MSG_RESTORE_OPERATION_TIMEOUT);
-
- // Verify that the backup set includes metadata. If not, we can't do
- // signature/version verification etc, so we simply do not proceed with
- // the restore operation.
- if (!mPmAgent.hasMetadata()) {
- Slog.e(TAG, "PM agent has no metadata, so not restoring");
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_PM_AGENT_HAS_NO_METADATA,
- mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
- EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
- PACKAGE_MANAGER_SENTINEL,
- "Package manager restore metadata missing");
- mStatus = BackupTransport.TRANSPORT_ERROR;
- mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this);
- executeNextState(UnifiedRestoreState.FINAL);
- return;
- }
-
- // Success; cache the metadata and continue as expected with the
- // next state already enqueued
-
- } catch (Exception e) {
- // If we lost the transport at any time, halt
- Slog.e(TAG, "Unable to contact transport for restore: " + e.getMessage());
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_LOST_TRANSPORT,
- null,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null);
- mStatus = BackupTransport.TRANSPORT_ERROR;
- mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this);
- executeNextState(UnifiedRestoreState.FINAL);
- return;
- }
- }
-
- // state RUNNING_QUEUE : figure out what the next thing to be restored is,
- // and fire the appropriate next step
- private void dispatchNextRestore() {
- UnifiedRestoreState nextState = UnifiedRestoreState.FINAL;
- try {
- mRestoreDescription = mTransport.nextRestorePackage();
- final String pkgName = (mRestoreDescription != null)
- ? mRestoreDescription.getPackageName() : null;
- if (pkgName == null) {
- Slog.e(TAG, "Failure getting next package name");
- EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
- nextState = UnifiedRestoreState.FINAL;
- return;
- } else if (mRestoreDescription == RestoreDescription.NO_MORE_PACKAGES) {
- // Yay we've reached the end cleanly
- if (DEBUG) {
- Slog.v(TAG, "No more packages; finishing restore");
- }
- int millis = (int) (SystemClock.elapsedRealtime() - mStartRealtime);
- EventLog.writeEvent(EventLogTags.RESTORE_SUCCESS, mCount, millis);
- nextState = UnifiedRestoreState.FINAL;
- return;
- }
-
- if (DEBUG) {
- Slog.i(TAG, "Next restore package: " + mRestoreDescription);
- }
- sendOnRestorePackage(pkgName);
-
- Metadata metaInfo = mPmAgent.getRestoredMetadata(pkgName);
- if (metaInfo == null) {
- Slog.e(TAG, "No metadata for " + pkgName);
- EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, pkgName,
- "Package metadata missing");
- nextState = UnifiedRestoreState.RUNNING_QUEUE;
- return;
- }
-
- try {
- mCurrentPackage = mPackageManager.getPackageInfo(
- pkgName, PackageManager.GET_SIGNATURES);
- } catch (NameNotFoundException e) {
- // Whoops, we thought we could restore this package but it
- // turns out not to be present. Skip it.
- Slog.e(TAG, "Package not present: " + pkgName);
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_NOT_PRESENT,
- mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- null);
- EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, pkgName,
- "Package missing on device");
- nextState = UnifiedRestoreState.RUNNING_QUEUE;
- return;
- }
-
- if (metaInfo.versionCode > mCurrentPackage.versionCode) {
- // Data is from a "newer" version of the app than we have currently
- // installed. If the app has not declared that it is prepared to
- // handle this case, we do not attempt the restore.
- if ((mCurrentPackage.applicationInfo.flags
- & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) == 0) {
- String message = "Source version " + metaInfo.versionCode
- + " > installed version " + mCurrentPackage.versionCode;
- Slog.w(TAG, "Package " + pkgName + ": " + message);
- Bundle monitoringExtras = putMonitoringExtra(null,
- BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION,
- metaInfo.versionCode);
- monitoringExtras = putMonitoringExtra(monitoringExtras,
- BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY, false);
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER,
- mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- monitoringExtras);
- EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
- pkgName, message);
- nextState = UnifiedRestoreState.RUNNING_QUEUE;
- return;
- } else {
- if (DEBUG) Slog.v(TAG, "Source version " + metaInfo.versionCode
- + " > installed version " + mCurrentPackage.versionCode
- + " but restoreAnyVersion");
- Bundle monitoringExtras = putMonitoringExtra(null,
- BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION,
- metaInfo.versionCode);
- monitoringExtras = putMonitoringExtra(monitoringExtras,
- BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY, true);
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER,
- mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- monitoringExtras);
- }
- }
-
- if (MORE_DEBUG) Slog.v(TAG, "Package " + pkgName
- + " restore version [" + metaInfo.versionCode
- + "] is compatible with installed version ["
- + mCurrentPackage.versionCode + "]");
-
- // Reset per-package preconditions and fire the appropriate next state
- mWidgetData = null;
- final int type = mRestoreDescription.getDataType();
- if (type == RestoreDescription.TYPE_KEY_VALUE) {
- nextState = UnifiedRestoreState.RESTORE_KEYVALUE;
- } else if (type == RestoreDescription.TYPE_FULL_STREAM) {
- nextState = UnifiedRestoreState.RESTORE_FULL;
- } else {
- // Unknown restore type; ignore this package and move on
- Slog.e(TAG, "Unrecognized restore type " + type);
- nextState = UnifiedRestoreState.RUNNING_QUEUE;
- return;
- }
- } catch (Exception e) {
- Slog.e(TAG, "Can't get next restore target from transport; halting: "
- + e.getMessage());
- EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
- nextState = UnifiedRestoreState.FINAL;
- return;
- } finally {
- executeNextState(nextState);
- }
- }
-
- // state RESTORE_KEYVALUE : restore one package via key/value API set
- private void restoreKeyValue() {
- // Initiating the restore will pass responsibility for the state machine's
- // progress to the agent callback, so we do not always execute the
- // next state here.
- final String packageName = mCurrentPackage.packageName;
- // Validate some semantic requirements that apply in this way
- // only to the key/value restore API flow
- if (mCurrentPackage.applicationInfo.backupAgentName == null
- || "".equals(mCurrentPackage.applicationInfo.backupAgentName)) {
- if (MORE_DEBUG) {
- Slog.i(TAG, "Data exists for package " + packageName
- + " but app has no agent; skipping");
- }
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_APP_HAS_NO_AGENT, mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null);
- EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
- "Package has no agent");
- executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
- return;
- }
-
- Metadata metaInfo = mPmAgent.getRestoredMetadata(packageName);
- if (!BackupUtils.signaturesMatch(metaInfo.sigHashes, mCurrentPackage)) {
- Slog.w(TAG, "Signature mismatch restoring " + packageName);
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_SIGNATURE_MISMATCH, mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
- EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
- "Signature mismatch");
- executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
- return;
- }
-
- // Good to go! Set up and bind the agent...
- mAgent = bindToAgentSynchronous(
- mCurrentPackage.applicationInfo,
- ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL);
- if (mAgent == null) {
- Slog.w(TAG, "Can't find backup agent for " + packageName);
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_CANT_FIND_AGENT, mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
- EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
- "Restore agent missing");
- executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
- return;
- }
-
- // Whatever happens next, we've launched the target app now; remember that.
- mDidLaunch = true;
-
- // And then finally start the restore on this agent
- try {
- initiateOneRestore(mCurrentPackage, metaInfo.versionCode);
- ++mCount;
- } catch (Exception e) {
- Slog.e(TAG, "Error when attempting restore: " + e.toString());
- keyValueAgentErrorCleanup();
- executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
- }
- }
-
- // Guts of a key/value restore operation
- void initiateOneRestore(PackageInfo app, int appVersionCode) {
- final String packageName = app.packageName;
-
- if (DEBUG) Slog.d(TAG, "initiateOneRestore packageName=" + packageName);
-
- // !!! TODO: get the dirs from the transport
- mBackupDataName = new File(mDataDir, packageName + ".restore");
- mStageName = new File(mDataDir, packageName + ".stage");
- mNewStateName = new File(mStateDir, packageName + ".new");
- mSavedStateName = new File(mStateDir, packageName);
-
- // don't stage the 'android' package where the wallpaper data lives. this is
- // an optimization: we know there's no widget data hosted/published by that
- // package, and this way we avoid doing a spurious copy of MB-sized wallpaper
- // data following the download.
- boolean staging = !packageName.equals("android");
- ParcelFileDescriptor stage;
- File downloadFile = (staging) ? mStageName : mBackupDataName;
-
- try {
- // Run the transport's restore pass
- stage = ParcelFileDescriptor.open(downloadFile,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE |
- ParcelFileDescriptor.MODE_TRUNCATE);
-
- if (mTransport.getRestoreData(stage) != BackupTransport.TRANSPORT_OK) {
- // Transport-level failure, so we wind everything up and
- // terminate the restore operation.
- Slog.e(TAG, "Error getting restore data for " + packageName);
- EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
- stage.close();
- downloadFile.delete();
- executeNextState(UnifiedRestoreState.FINAL);
- return;
- }
-
- // We have the data from the transport. Now we extract and strip
- // any per-package metadata (typically widget-related information)
- // if appropriate
- if (staging) {
- stage.close();
- stage = ParcelFileDescriptor.open(downloadFile,
- ParcelFileDescriptor.MODE_READ_ONLY);
-
- mBackupData = ParcelFileDescriptor.open(mBackupDataName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE |
- ParcelFileDescriptor.MODE_TRUNCATE);
-
- BackupDataInput in = new BackupDataInput(stage.getFileDescriptor());
- BackupDataOutput out = new BackupDataOutput(mBackupData.getFileDescriptor());
- byte[] buffer = new byte[8192]; // will grow when needed
- while (in.readNextHeader()) {
- final String key = in.getKey();
- final int size = in.getDataSize();
-
- // is this a special key?
- if (key.equals(KEY_WIDGET_STATE)) {
- if (DEBUG) {
- Slog.i(TAG, "Restoring widget state for " + packageName);
- }
- mWidgetData = new byte[size];
- in.readEntityData(mWidgetData, 0, size);
- } else {
- if (size > buffer.length) {
- buffer = new byte[size];
- }
- in.readEntityData(buffer, 0, size);
- out.writeEntityHeader(key, size);
- out.writeEntityData(buffer, size);
- }
- }
-
- mBackupData.close();
- }
-
- // Okay, we have the data. Now have the agent do the restore.
- stage.close();
-
- mBackupData = ParcelFileDescriptor.open(mBackupDataName,
- ParcelFileDescriptor.MODE_READ_ONLY);
-
- mNewState = ParcelFileDescriptor.open(mNewStateName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE |
- ParcelFileDescriptor.MODE_TRUNCATE);
-
- // Kick off the restore, checking for hung agents. The timeout or
- // the operationComplete() callback will schedule the next step,
- // so we do not do that here.
- prepareOperationTimeout(mEphemeralOpToken, TIMEOUT_RESTORE_INTERVAL,
- this, OP_TYPE_RESTORE_WAIT);
- mAgent.doRestore(mBackupData, appVersionCode, mNewState,
- mEphemeralOpToken, mBackupManagerBinder);
- } catch (Exception e) {
- Slog.e(TAG, "Unable to call app for restore: " + packageName, e);
- EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
- packageName, e.toString());
- keyValueAgentErrorCleanup(); // clears any pending timeout messages as well
-
- // After a restore failure we go back to running the queue. If there
- // are no more packages to be restored that will be handled by the
- // next step.
- executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
- }
- }
-
- // state RESTORE_FULL : restore one package via streaming engine
- private void restoreFull() {
- // None of this can run on the work looper here, so we spin asynchronous
- // work like this:
- //
- // StreamFeederThread: read data from mTransport.getNextFullRestoreDataChunk()
- // write it into the pipe to the engine
- // EngineThread: FullRestoreEngine thread communicating with the target app
- //
- // When finished, StreamFeederThread executes next state as appropriate on the
- // backup looper, and the overall unified restore task resumes
- try {
- StreamFeederThread feeder = new StreamFeederThread();
- if (MORE_DEBUG) {
- Slog.i(TAG, "Spinning threads for stream restore of "
- + mCurrentPackage.packageName);
- }
- new Thread(feeder, "unified-stream-feeder").start();
-
- // At this point the feeder is responsible for advancing the restore
- // state, so we're done here.
- } catch (IOException e) {
- // Unable to instantiate the feeder thread -- we need to bail on the
- // current target. We haven't asked the transport for data yet, though,
- // so we can do that simply by going back to running the restore queue.
- Slog.e(TAG, "Unable to construct pipes for stream restore!");
- executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
- }
- }
-
- // state RESTORE_FINISHED : provide the "no more data" signpost callback at the end
- private void restoreFinished() {
- if (DEBUG) {
- Slog.d(TAG, "restoreFinished packageName=" + mCurrentPackage.packageName);
- }
- try {
- prepareOperationTimeout(mEphemeralOpToken, TIMEOUT_RESTORE_FINISHED_INTERVAL, this,
- OP_TYPE_RESTORE_WAIT);
- mAgent.doRestoreFinished(mEphemeralOpToken, mBackupManagerBinder);
- // If we get this far, the callback or timeout will schedule the
- // next restore state, so we're done
- } catch (Exception e) {
- final String packageName = mCurrentPackage.packageName;
- Slog.e(TAG, "Unable to finalize restore of " + packageName);
- EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
- packageName, e.toString());
- keyValueAgentErrorCleanup();
- executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
- }
- }
-
- class StreamFeederThread extends RestoreEngine implements Runnable, BackupRestoreTask {
- final String TAG = "StreamFeederThread";
- FullRestoreEngine mEngine;
- EngineThread mEngineThread;
-
- // pipe through which we read data from the transport. [0] read, [1] write
- ParcelFileDescriptor[] mTransportPipes;
-
- // pipe through which the engine will read data. [0] read, [1] write
- ParcelFileDescriptor[] mEnginePipes;
-
- private final int mEphemeralOpToken;
-
- public StreamFeederThread() throws IOException {
- mEphemeralOpToken = generateRandomIntegerToken();
- mTransportPipes = ParcelFileDescriptor.createPipe();
- mEnginePipes = ParcelFileDescriptor.createPipe();
- setRunning(true);
- }
-
- @Override
- public void run() {
- UnifiedRestoreState nextState = UnifiedRestoreState.RUNNING_QUEUE;
- int status = BackupTransport.TRANSPORT_OK;
-
- EventLog.writeEvent(EventLogTags.FULL_RESTORE_PACKAGE,
- mCurrentPackage.packageName);
-
- mEngine = new FullRestoreEngine(this, null, mMonitor, mCurrentPackage, false, false, mEphemeralOpToken);
- mEngineThread = new EngineThread(mEngine, mEnginePipes[0]);
-
- ParcelFileDescriptor eWriteEnd = mEnginePipes[1];
- ParcelFileDescriptor tReadEnd = mTransportPipes[0];
- ParcelFileDescriptor tWriteEnd = mTransportPipes[1];
-
- int bufferSize = 32 * 1024;
- byte[] buffer = new byte[bufferSize];
- FileOutputStream engineOut = new FileOutputStream(eWriteEnd.getFileDescriptor());
- FileInputStream transportIn = new FileInputStream(tReadEnd.getFileDescriptor());
-
- // spin up the engine and start moving data to it
- new Thread(mEngineThread, "unified-restore-engine").start();
-
- try {
- while (status == BackupTransport.TRANSPORT_OK) {
- // have the transport write some of the restoring data to us
- int result = mTransport.getNextFullRestoreDataChunk(tWriteEnd);
- if (result > 0) {
- // The transport wrote this many bytes of restore data to the
- // pipe, so pass it along to the engine.
- if (MORE_DEBUG) {
- Slog.v(TAG, " <- transport provided chunk size " + result);
- }
- if (result > bufferSize) {
- bufferSize = result;
- buffer = new byte[bufferSize];
- }
- int toCopy = result;
- while (toCopy > 0) {
- int n = transportIn.read(buffer, 0, toCopy);
- engineOut.write(buffer, 0, n);
- toCopy -= n;
- if (MORE_DEBUG) {
- Slog.v(TAG, " -> wrote " + n + " to engine, left=" + toCopy);
- }
- }
- } else if (result == BackupTransport.NO_MORE_DATA) {
- // Clean finish. Wind up and we're done!
- if (MORE_DEBUG) {
- Slog.i(TAG, "Got clean full-restore EOF for "
- + mCurrentPackage.packageName);
- }
- status = BackupTransport.TRANSPORT_OK;
- break;
- } else {
- // Transport reported some sort of failure; the fall-through
- // handling will deal properly with that.
- Slog.e(TAG, "Error " + result + " streaming restore for "
- + mCurrentPackage.packageName);
- EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
- status = result;
- }
- }
- if (MORE_DEBUG) Slog.v(TAG, "Done copying to engine, falling through");
- } catch (IOException e) {
- // We lost our ability to communicate via the pipes. That's worrying
- // but potentially recoverable; abandon this package's restore but
- // carry on with the next restore target.
- Slog.e(TAG, "Unable to route data for restore");
- EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
- mCurrentPackage.packageName, "I/O error on pipes");
- status = BackupTransport.AGENT_ERROR;
- } catch (Exception e) {
- // The transport threw; terminate the whole operation. Closing
- // the sockets will wake up the engine and it will then tidy up the
- // remote end.
- Slog.e(TAG, "Transport failed during restore: " + e.getMessage());
- EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
- status = BackupTransport.TRANSPORT_ERROR;
- } finally {
- // Close the transport pipes and *our* end of the engine pipe,
- // but leave the engine thread's end open so that it properly
- // hits EOF and winds up its operations.
- IoUtils.closeQuietly(mEnginePipes[1]);
- IoUtils.closeQuietly(mTransportPipes[0]);
- IoUtils.closeQuietly(mTransportPipes[1]);
-
- // Don't proceed until the engine has wound up operations
- mEngineThread.waitForResult();
-
- // Now we're really done with this one too
- IoUtils.closeQuietly(mEnginePipes[0]);
-
- // In all cases we want to remember whether we launched
- // the target app as part of our work so far.
- mDidLaunch = (mEngine.getAgent() != null);
-
- // If we hit a transport-level error, we are done with everything;
- // if we hit an agent error we just go back to running the queue.
- if (status == BackupTransport.TRANSPORT_OK) {
- // Clean finish means we issue the restore-finished callback
- nextState = UnifiedRestoreState.RESTORE_FINISHED;
-
- // the engine bound the target's agent, so recover that binding
- // to use for the callback.
- mAgent = mEngine.getAgent();
-
- // and the restored widget data, if any
- mWidgetData = mEngine.getWidgetData();
- } else {
- // Something went wrong somewhere. Whether it was at the transport
- // level is immaterial; we need to tell the transport to bail
- try {
- mTransport.abortFullRestore();
- } catch (Exception e) {
- // transport itself is dead; make sure we handle this as a
- // fatal error
- Slog.e(TAG, "Transport threw from abortFullRestore: " + e.getMessage());
- status = BackupTransport.TRANSPORT_ERROR;
- }
-
- // We also need to wipe the current target's data, as it's probably
- // in an incoherent state.
- clearApplicationDataSynchronous(mCurrentPackage.packageName);
-
- // Schedule the next state based on the nature of our failure
- if (status == BackupTransport.TRANSPORT_ERROR) {
- nextState = UnifiedRestoreState.FINAL;
- } else {
- nextState = UnifiedRestoreState.RUNNING_QUEUE;
- }
- }
- executeNextState(nextState);
- setRunning(false);
- }
- }
-
- // BackupRestoreTask interface, specifically for timeout handling
-
- @Override
- public void execute() { /* intentionally empty */ }
-
- @Override
- public void operationComplete(long result) { /* intentionally empty */ }
-
- // The app has timed out handling a restoring file
- @Override
- public void handleCancel(boolean cancelAll) {
- removeOperation(mEphemeralOpToken);
- if (DEBUG) {
- Slog.w(TAG, "Full-data restore target timed out; shutting down");
- }
-
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_TIMEOUT,
- mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null);
- mEngineThread.handleTimeout();
-
- IoUtils.closeQuietly(mEnginePipes[1]);
- mEnginePipes[1] = null;
- IoUtils.closeQuietly(mEnginePipes[0]);
- mEnginePipes[0] = null;
- }
- }
-
- class EngineThread implements Runnable {
- FullRestoreEngine mEngine;
- FileInputStream mEngineStream;
-
- EngineThread(FullRestoreEngine engine, ParcelFileDescriptor engineSocket) {
- mEngine = engine;
- engine.setRunning(true);
- // We *do* want this FileInputStream to own the underlying fd, so that
- // when we are finished with it, it closes this end of the pipe in a way
- // that signals its other end.
- mEngineStream = new FileInputStream(engineSocket.getFileDescriptor(), true);
- }
-
- public boolean isRunning() {
- return mEngine.isRunning();
- }
-
- public int waitForResult() {
- return mEngine.waitForResult();
- }
-
- @Override
- public void run() {
- try {
- while (mEngine.isRunning()) {
- // Tell it to be sure to leave the agent instance up after finishing
- mEngine.restoreOneFile(mEngineStream, false);
- }
- } finally {
- // Because mEngineStream adopted its underlying FD, this also
- // closes this end of the pipe.
- IoUtils.closeQuietly(mEngineStream);
- }
- }
-
- public void handleTimeout() {
- IoUtils.closeQuietly(mEngineStream);
- mEngine.handleTimeout();
- }
- }
-
- // state FINAL : tear everything down and we're done.
- private void finalizeRestore() {
- if (MORE_DEBUG) Slog.d(TAG, "finishing restore mObserver=" + mObserver);
-
- try {
- mTransport.finishRestore();
- } catch (Exception e) {
- Slog.e(TAG, "Error finishing restore", e);
- }
-
- // Tell the observer we're done
- if (mObserver != null) {
- try {
- mObserver.restoreFinished(mStatus);
- } catch (RemoteException e) {
- Slog.d(TAG, "Restore observer died at restoreFinished");
- }
- }
-
- // Clear any ongoing session timeout.
- mBackupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
-
- // If we have a PM token, we must under all circumstances be sure to
- // handshake when we've finished.
- if (mPmToken > 0) {
- if (MORE_DEBUG) Slog.v(TAG, "finishing PM token " + mPmToken);
- try {
- mPackageManagerBinder.finishPackageInstall(mPmToken, mDidLaunch);
- } catch (RemoteException e) { /* can't happen */ }
- } else {
- // We were invoked via an active restore session, not by the Package
- // Manager, so start up the session timeout again.
- mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT,
- TIMEOUT_RESTORE_INTERVAL);
- }
-
- // Kick off any work that may be needed regarding app widget restores
- // TODO: http://b/22388012
- AppWidgetBackupBridge.restoreFinished(UserHandle.USER_SYSTEM);
-
- // If this was a full-system restore, record the ancestral
- // dataset information
- if (mIsSystemRestore && mPmAgent != null) {
- mAncestralPackages = mPmAgent.getRestoredPackages();
- mAncestralToken = mToken;
- writeRestoreTokens();
- }
-
- // done; we can finally release the wakelock and be legitimately done.
- Slog.i(TAG, "Restore complete.");
-
- synchronized (mPendingRestores) {
- if (mPendingRestores.size() > 0) {
- if (DEBUG) {
- Slog.d(TAG, "Starting next pending restore.");
- }
- PerformUnifiedRestoreTask task = mPendingRestores.remove();
- mBackupHandler.sendMessage(
- mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, task));
-
- } else {
- mIsRestoreInProgress = false;
- if (MORE_DEBUG) {
- Slog.d(TAG, "No pending restores.");
- }
- }
- }
-
- mWakelock.release();
- }
-
- void keyValueAgentErrorCleanup() {
- // If the agent fails restore, it might have put the app's data
- // into an incoherent state. For consistency we wipe its data
- // again in this case before continuing with normal teardown
- clearApplicationDataSynchronous(mCurrentPackage.packageName);
- keyValueAgentCleanup();
- }
-
- // TODO: clean up naming; this is now used at finish by both k/v and stream restores
- void keyValueAgentCleanup() {
- mBackupDataName.delete();
- mStageName.delete();
- try { if (mBackupData != null) mBackupData.close(); } catch (IOException e) {}
- try { if (mNewState != null) mNewState.close(); } catch (IOException e) {}
- mBackupData = mNewState = null;
-
- // if everything went okay, remember the recorded state now
- //
- // !!! TODO: the restored data could be migrated on the server
- // side into the current dataset. In that case the new state file
- // we just created would reflect the data already extant in the
- // backend, so there'd be nothing more to do. Until that happens,
- // however, we need to make sure that we record the data to the
- // current backend dataset. (Yes, this means shipping the data over
- // the wire in both directions. That's bad, but consistency comes
- // first, then efficiency.) Once we introduce server-side data
- // migration to the newly-restored device's dataset, we will change
- // the following from a discard of the newly-written state to the
- // "correct" operation of renaming into the canonical state blob.
- mNewStateName.delete(); // TODO: remove; see above comment
- //mNewStateName.renameTo(mSavedStateName); // TODO: replace with this
-
- // If this wasn't the PM pseudopackage, tear down the agent side
- if (mCurrentPackage.applicationInfo != null) {
- // unbind and tidy up even on timeout or failure
- try {
- mActivityManager.unbindBackupAgent(mCurrentPackage.applicationInfo);
-
- // The agent was probably running with a stub Application object,
- // which isn't a valid run mode for the main app logic. Shut
- // down the app so that next time it's launched, it gets the
- // usual full initialization. Note that this is only done for
- // full-system restores: when a single app has requested a restore,
- // it is explicitly not killed following that operation.
- //
- // We execute this kill when these conditions hold:
- // 1. it's not a system-uid process,
- // 2. the app did not request its own restore (mTargetPackage == null), and either
- // 3a. the app is a full-data target (TYPE_FULL_STREAM) or
- // b. the app does not state android:killAfterRestore="false" in its manifest
- final int appFlags = mCurrentPackage.applicationInfo.flags;
- final boolean killAfterRestore =
- (mCurrentPackage.applicationInfo.uid >= Process.FIRST_APPLICATION_UID)
- && ((mRestoreDescription.getDataType() == RestoreDescription.TYPE_FULL_STREAM)
- || ((appFlags & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0));
-
- if (mTargetPackage == null && killAfterRestore) {
- if (DEBUG) Slog.d(TAG, "Restore complete, killing host process of "
- + mCurrentPackage.applicationInfo.processName);
- mActivityManager.killApplicationProcess(
- mCurrentPackage.applicationInfo.processName,
- mCurrentPackage.applicationInfo.uid);
- }
- } catch (RemoteException e) {
- // can't happen; we run in the same process as the activity manager
- }
- }
-
- // The caller is responsible for reestablishing the state machine; our
- // responsibility here is to clear the decks for whatever comes next.
- mBackupHandler.removeMessages(MSG_RESTORE_OPERATION_TIMEOUT, this);
- }
-
- @Override
- public void operationComplete(long unusedResult) {
- removeOperation(mEphemeralOpToken);
- if (MORE_DEBUG) {
- Slog.i(TAG, "operationComplete() during restore: target="
- + mCurrentPackage.packageName
- + " state=" + mState);
- }
-
- final UnifiedRestoreState nextState;
- switch (mState) {
- case INITIAL:
- // We've just (manually) restored the PMBA. It doesn't need the
- // additional restore-finished callback so we bypass that and go
- // directly to running the queue.
- nextState = UnifiedRestoreState.RUNNING_QUEUE;
- break;
-
- case RESTORE_KEYVALUE:
- case RESTORE_FULL: {
- // Okay, we've just heard back from the agent that it's done with
- // the restore itself. We now have to send the same agent its
- // doRestoreFinished() callback, so roll into that state.
- nextState = UnifiedRestoreState.RESTORE_FINISHED;
- break;
- }
-
- case RESTORE_FINISHED: {
- // Okay, we're done with this package. Tidy up and go on to the next
- // app in the queue.
- int size = (int) mBackupDataName.length();
- EventLog.writeEvent(EventLogTags.RESTORE_PACKAGE,
- mCurrentPackage.packageName, size);
-
- // Just go back to running the restore queue
- keyValueAgentCleanup();
-
- // If there was widget state associated with this app, get the OS to
- // incorporate it into current bookeeping and then pass that along to
- // the app as part of the restore-time work.
- if (mWidgetData != null) {
- restoreWidgetData(mCurrentPackage.packageName, mWidgetData);
- }
-
- nextState = UnifiedRestoreState.RUNNING_QUEUE;
- break;
- }
-
- default: {
- // Some kind of horrible semantic error; we're in an unexpected state.
- // Back off hard and wind up.
- Slog.e(TAG, "Unexpected restore callback into state " + mState);
- keyValueAgentErrorCleanup();
- nextState = UnifiedRestoreState.FINAL;
- break;
- }
- }
-
- executeNextState(nextState);
- }
-
- // A call to agent.doRestore() or agent.doRestoreFinished() has timed out
- @Override
- public void handleCancel(boolean cancelAll) {
- removeOperation(mEphemeralOpToken);
- Slog.e(TAG, "Timeout restoring application " + mCurrentPackage.packageName);
- mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_RESTORE_TIMEOUT,
- mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null);
- EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
- mCurrentPackage.packageName, "restore timeout");
- // Handle like an agent that threw on invocation: wipe it and go on to the next
- keyValueAgentErrorCleanup();
- executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
- }
-
- void executeNextState(UnifiedRestoreState nextState) {
- if (MORE_DEBUG) Slog.i(TAG, " => executing next step on "
- + this + " nextState=" + nextState);
- mState = nextState;
- Message msg = mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, this);
- mBackupHandler.sendMessage(msg);
- }
-
- // restore observer support
- void sendStartRestore(int numPackages) {
- if (mObserver != null) {
- try {
- mObserver.restoreStarting(numPackages);
- } catch (RemoteException e) {
- Slog.w(TAG, "Restore observer went away: startRestore");
- mObserver = null;
- }
- }
- }
-
- void sendOnRestorePackage(String name) {
- if (mObserver != null) {
- if (mObserver != null) {
- try {
- mObserver.onUpdate(mCount, name);
- } catch (RemoteException e) {
- Slog.d(TAG, "Restore observer died in onUpdate");
- mObserver = null;
- }
- }
- }
- }
-
- void sendEndRestore() {
- if (mObserver != null) {
- try {
- mObserver.restoreFinished(mStatus);
- } catch (RemoteException e) {
- Slog.w(TAG, "Restore observer went away: endRestore");
- mObserver = null;
- }
- }
- }
- }
-
- class PerformClearTask implements Runnable {
- IBackupTransport mTransport;
- PackageInfo mPackage;
-
- PerformClearTask(IBackupTransport transport, PackageInfo packageInfo) {
- mTransport = transport;
- mPackage = packageInfo;
- }
-
- public void run() {
- try {
- // Clear the on-device backup state to ensure a full backup next time
- File stateDir = new File(mBaseStateDir, mTransport.transportDirName());
- File stateFile = new File(stateDir, mPackage.packageName);
- stateFile.delete();
-
- // Tell the transport to remove all the persistent storage for the app
- // TODO - need to handle failures
- mTransport.clearBackupData(mPackage);
- } catch (Exception e) {
- Slog.e(TAG, "Transport threw clearing data for " + mPackage + ": " + e.getMessage());
- } finally {
- try {
- // TODO - need to handle failures
- mTransport.finishBackup();
- } catch (Exception e) {
- // Nothing we can do here, alas
- Slog.e(TAG, "Unable to mark clear operation finished: " + e.getMessage());
- }
-
- // Last but not least, release the cpu
- mWakelock.release();
- }
- }
- }
-
- class PerformInitializeTask implements Runnable {
- String[] mQueue;
- IBackupObserver mObserver;
-
- PerformInitializeTask(String[] transportNames, IBackupObserver observer) {
- mQueue = transportNames;
- mObserver = observer;
- }
-
- private void notifyResult(String target, int status) {
- try {
- if (mObserver != null) {
- mObserver.onResult(target, status);
- }
- } catch (RemoteException ignored) {
- mObserver = null; // don't try again
- }
- }
-
- private void notifyFinished(int status) {
- try {
- if (mObserver != null) {
- mObserver.backupFinished(status);
- }
- } catch (RemoteException ignored) {
- mObserver = null;
- }
- }
-
- public void run() {
- // mWakelock is *acquired* when execution begins here
- int result = BackupTransport.TRANSPORT_OK;
- try {
- for (String transportName : mQueue) {
- IBackupTransport transport =
- mTransportManager.getTransportBinder(transportName);
- if (transport == null) {
- Slog.e(TAG, "Requested init for " + transportName + " but not found");
- continue;
- }
-
- Slog.i(TAG, "Initializing (wiping) backup transport storage: " + transportName);
- String transportDirName = transport.transportDirName();
- EventLog.writeEvent(EventLogTags.BACKUP_START, transportDirName);
- long startRealtime = SystemClock.elapsedRealtime();
- int status = transport.initializeDevice();
-
- if (status == BackupTransport.TRANSPORT_OK) {
- status = transport.finishBackup();
- }
-
- // Okay, the wipe really happened. Clean up our local bookkeeping.
- if (status == BackupTransport.TRANSPORT_OK) {
- Slog.i(TAG, "Device init successful");
- int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
- EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
- resetBackupState(new File(mBaseStateDir, transportDirName));
- EventLog.writeEvent(EventLogTags.BACKUP_SUCCESS, 0, millis);
- synchronized (mQueueLock) {
- recordInitPendingLocked(false, transportName);
- }
- notifyResult(transportName, BackupTransport.TRANSPORT_OK);
- } else {
- // If this didn't work, requeue this one and try again
- // after a suitable interval
- Slog.e(TAG, "Transport error in initializeDevice()");
- EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
- synchronized (mQueueLock) {
- recordInitPendingLocked(true, transportName);
- }
- notifyResult(transportName, status);
- result = status;
-
- // do this via another alarm to make sure of the wakelock states
- long delay = transport.requestBackupTime();
- Slog.w(TAG, "Init failed on " + transportName + " resched in " + delay);
- mAlarmManager.set(AlarmManager.RTC_WAKEUP,
- System.currentTimeMillis() + delay, mRunInitIntent);
- }
- }
- } catch (Exception e) {
- Slog.e(TAG, "Unexpected error performing init", e);
- result = BackupTransport.TRANSPORT_ERROR;
- } finally {
- // Done; release the wakelock
- notifyFinished(result);
- mWakelock.release();
- }
- }
- }
-
- private void dataChangedImpl(String packageName) {
- HashSet<String> targets = dataChangedTargets(packageName);
- dataChangedImpl(packageName, targets);
- }
-
- private void dataChangedImpl(String packageName, HashSet<String> targets) {
- // Record that we need a backup pass for the caller. Since multiple callers
- // may share a uid, we need to note all candidates within that uid and schedule
- // a backup pass for each of them.
- if (targets == null) {
- Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
- + " uid=" + Binder.getCallingUid());
- return;
- }
-
- synchronized (mQueueLock) {
- // Note that this client has made data changes that need to be backed up
- if (targets.contains(packageName)) {
- // Add the caller to the set of pending backups. If there is
- // one already there, then overwrite it, but no harm done.
- BackupRequest req = new BackupRequest(packageName);
- if (mPendingBackups.put(packageName, req) == null) {
- if (MORE_DEBUG) Slog.d(TAG, "Now staging backup of " + packageName);
-
- // Journal this request in case of crash. The put()
- // operation returned null when this package was not already
- // in the set; we want to avoid touching the disk redundantly.
- writeToJournalLocked(packageName);
- }
- }
- }
-
- // ...and schedule a backup pass if necessary
- KeyValueBackupJob.schedule(mContext, mConstants);
- }
-
- // Note: packageName is currently unused, but may be in the future
- private HashSet<String> dataChangedTargets(String packageName) {
- // If the caller does not hold the BACKUP permission, it can only request a
- // backup of its own data.
- if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
- Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
- synchronized (mBackupParticipants) {
- return mBackupParticipants.get(Binder.getCallingUid());
- }
- }
-
- // a caller with full permission can ask to back up any participating app
- HashSet<String> targets = new HashSet<String>();
- if (PACKAGE_MANAGER_SENTINEL.equals(packageName)) {
- targets.add(PACKAGE_MANAGER_SENTINEL);
- } else {
- synchronized (mBackupParticipants) {
- int N = mBackupParticipants.size();
- for (int i = 0; i < N; i++) {
- HashSet<String> s = mBackupParticipants.valueAt(i);
- if (s != null) {
- targets.addAll(s);
- }
- }
- }
- }
- return targets;
- }
-
- private void writeToJournalLocked(String str) {
- RandomAccessFile out = null;
- try {
- if (mJournal == null) mJournal = File.createTempFile("journal", null, mJournalDir);
- out = new RandomAccessFile(mJournal, "rws");
- out.seek(out.length());
- out.writeUTF(str);
- } catch (IOException e) {
- Slog.e(TAG, "Can't write " + str + " to backup journal", e);
- mJournal = null;
- } finally {
- try { if (out != null) out.close(); } catch (IOException e) {}
- }
- }
-
- // ----- IBackupManager binder interface -----
-
- @Override
- public void dataChanged(final String packageName) {
- final int callingUserHandle = UserHandle.getCallingUserId();
- if (callingUserHandle != UserHandle.USER_SYSTEM) {
- // TODO: http://b/22388012
- // App is running under a non-owner user profile. For now, we do not back
- // up data from secondary user profiles.
- // TODO: backups for all user profiles although don't add backup for profiles
- // without adding admin control in DevicePolicyManager.
- if (MORE_DEBUG) {
- Slog.v(TAG, "dataChanged(" + packageName + ") ignored because it's user "
- + callingUserHandle);
- }
- return;
- }
-
- final HashSet<String> targets = dataChangedTargets(packageName);
- if (targets == null) {
- Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
- + " uid=" + Binder.getCallingUid());
- return;
- }
-
- mBackupHandler.post(new Runnable() {
- public void run() {
- dataChangedImpl(packageName, targets);
- }
- });
- }
-
- // Run an initialize operation for the given transport
- @Override
- public void initializeTransports(String[] transportNames, IBackupObserver observer) {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "initializeTransport");
- if (MORE_DEBUG) {
- Slog.v(TAG, "initializeTransports() of " + transportNames);
- }
-
- final long oldId = Binder.clearCallingIdentity();
- try {
- mWakelock.acquire();
- mBackupHandler.post(new PerformInitializeTask(transportNames, observer));
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
- }
-
- // Clear the given package's backup data from the current transport
- @Override
- public void clearBackupData(String transportName, String packageName) {
- if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName + " on " + transportName);
- PackageInfo info;
- try {
- info = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
- } catch (NameNotFoundException e) {
- Slog.d(TAG, "No such package '" + packageName + "' - not clearing backup data");
- return;
- }
-
- // If the caller does not hold the BACKUP permission, it can only request a
- // wipe of its own backed-up data.
- HashSet<String> apps;
- if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
- Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
- apps = mBackupParticipants.get(Binder.getCallingUid());
- } else {
- // a caller with full permission can ask to back up any participating app
- // !!! TODO: allow data-clear of ANY app?
- if (MORE_DEBUG) Slog.v(TAG, "Privileged caller, allowing clear of other apps");
- apps = new HashSet<String>();
- int N = mBackupParticipants.size();
- for (int i = 0; i < N; i++) {
- HashSet<String> s = mBackupParticipants.valueAt(i);
- if (s != null) {
- apps.addAll(s);
- }
- }
- }
-
- // Is the given app an available participant?
- if (apps.contains(packageName)) {
- // found it; fire off the clear request
- if (MORE_DEBUG) Slog.v(TAG, "Found the app - running clear process");
- mBackupHandler.removeMessages(MSG_RETRY_CLEAR);
- synchronized (mQueueLock) {
- final IBackupTransport transport =
- mTransportManager.getTransportBinder(transportName);
- if (transport == null) {
- // transport is currently unavailable -- make sure to retry
- Message msg = mBackupHandler.obtainMessage(MSG_RETRY_CLEAR,
- new ClearRetryParams(transportName, packageName));
- mBackupHandler.sendMessageDelayed(msg, TRANSPORT_RETRY_INTERVAL);
- return;
- }
- long oldId = Binder.clearCallingIdentity();
- mWakelock.acquire();
- Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
- new ClearParams(transport, info));
- mBackupHandler.sendMessage(msg);
- Binder.restoreCallingIdentity(oldId);
- }
- }
- }
-
- // Run a backup pass immediately for any applications that have declared
- // that they have pending updates.
- @Override
- public void backupNow() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow");
-
- final PowerSaveState result =
- mPowerManager.getPowerSaveState(ServiceType.KEYVALUE_BACKUP);
- if (result.batterySaverEnabled) {
- if (DEBUG) Slog.v(TAG, "Not running backup while in battery save mode");
- KeyValueBackupJob.schedule(mContext, mConstants); // try again in several hours
- } else {
- if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass");
- synchronized (mQueueLock) {
- // Fire the intent that kicks off the whole shebang...
- try {
- mRunBackupIntent.send();
- } catch (PendingIntent.CanceledException e) {
- // should never happen
- Slog.e(TAG, "run-backup intent cancelled!");
- }
-
- // ...and cancel any pending scheduled job, because we've just superseded it
- KeyValueBackupJob.cancel(mContext);
- }
- }
- }
-
- boolean deviceIsProvisioned() {
- final ContentResolver resolver = mContext.getContentResolver();
- return (Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0);
- }
-
- // Run a backup pass for the given packages, writing the resulting data stream
- // to the supplied file descriptor. This method is synchronous and does not return
- // to the caller until the backup has been completed.
- //
- // This is the variant used by 'adb backup'; it requires on-screen confirmation
- // by the user because it can be used to offload data over untrusted USB.
- @Override
- public void adbBackup(ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs,
- boolean includeShared, boolean doWidgets, boolean doAllApps, boolean includeSystem,
- boolean compress, boolean doKeyValue, String[] pkgList) {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "adbBackup");
-
- final int callingUserHandle = UserHandle.getCallingUserId();
- // TODO: http://b/22388012
- if (callingUserHandle != UserHandle.USER_SYSTEM) {
- throw new IllegalStateException("Backup supported only for the device owner");
- }
-
- // Validate
- if (!doAllApps) {
- if (!includeShared) {
- // If we're backing up shared data (sdcard or equivalent), then we can run
- // without any supplied app names. Otherwise, we'd be doing no work, so
- // report the error.
- if (pkgList == null || pkgList.length == 0) {
- throw new IllegalArgumentException(
- "Backup requested but neither shared nor any apps named");
- }
- }
- }
-
- long oldId = Binder.clearCallingIdentity();
- try {
- // Doesn't make sense to do a full backup prior to setup
- if (!deviceIsProvisioned()) {
- Slog.i(TAG, "Backup not supported before setup");
- return;
- }
-
- if (DEBUG) Slog.v(TAG, "Requesting backup: apks=" + includeApks + " obb=" + includeObbs
- + " shared=" + includeShared + " all=" + doAllApps + " system="
- + includeSystem + " includekeyvalue=" + doKeyValue + " pkgs=" + pkgList);
- Slog.i(TAG, "Beginning adb backup...");
-
- AdbBackupParams params = new AdbBackupParams(fd, includeApks, includeObbs,
- includeShared, doWidgets, doAllApps, includeSystem, compress, doKeyValue,
- pkgList);
- final int token = generateRandomIntegerToken();
- synchronized (mAdbBackupRestoreConfirmations) {
- mAdbBackupRestoreConfirmations.put(token, params);
- }
-
- // start up the confirmation UI
- if (DEBUG) Slog.d(TAG, "Starting backup confirmation UI, token=" + token);
- if (!startConfirmationUi(token, FullBackup.FULL_BACKUP_INTENT_ACTION)) {
- Slog.e(TAG, "Unable to launch backup confirmation UI");
- mAdbBackupRestoreConfirmations.delete(token);
- return;
- }
-
- // make sure the screen is lit for the user interaction
- mPowerManager.userActivity(SystemClock.uptimeMillis(),
- PowerManager.USER_ACTIVITY_EVENT_OTHER,
- 0);
-
- // start the confirmation countdown
- startConfirmationTimeout(token, params);
-
- // wait for the backup to be performed
- if (DEBUG) Slog.d(TAG, "Waiting for backup completion...");
- waitForCompletion(params);
- } finally {
- try {
- fd.close();
- } catch (IOException e) {
- Slog.e(TAG, "IO error closing output for adb backup: " + e.getMessage());
- }
- Binder.restoreCallingIdentity(oldId);
- Slog.d(TAG, "Adb backup processing complete.");
- }
- }
-
- @Override
- public void fullTransportBackup(String[] pkgNames) {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
- "fullTransportBackup");
-
- final int callingUserHandle = UserHandle.getCallingUserId();
- // TODO: http://b/22388012
- if (callingUserHandle != UserHandle.USER_SYSTEM) {
- throw new IllegalStateException("Restore supported only for the device owner");
- }
-
- if (!fullBackupAllowable(mTransportManager.getCurrentTransportBinder())) {
- Slog.i(TAG, "Full backup not currently possible -- key/value backup not yet run?");
- } else {
- if (DEBUG) {
- Slog.d(TAG, "fullTransportBackup()");
- }
-
- final long oldId = Binder.clearCallingIdentity();
- try {
- CountDownLatch latch = new CountDownLatch(1);
- PerformFullTransportBackupTask task = new PerformFullTransportBackupTask(null,
- pkgNames, false, null, latch, null, null, false /* userInitiated */);
- // Acquiring wakelock for PerformFullTransportBackupTask before its start.
- mWakelock.acquire();
- (new Thread(task, "full-transport-master")).start();
- do {
- try {
- latch.await();
- break;
- } catch (InterruptedException e) {
- // Just go back to waiting for the latch to indicate completion
- }
- } while (true);
-
- // We just ran a backup on these packages, so kick them to the end of the queue
- final long now = System.currentTimeMillis();
- for (String pkg : pkgNames) {
- enqueueFullBackup(pkg, now);
- }
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
- }
-
- if (DEBUG) {
- Slog.d(TAG, "Done with full transport backup.");
- }
- }
-
- @Override
- public void adbRestore(ParcelFileDescriptor fd) {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "adbRestore");
-
- final int callingUserHandle = UserHandle.getCallingUserId();
- // TODO: http://b/22388012
- if (callingUserHandle != UserHandle.USER_SYSTEM) {
- throw new IllegalStateException("Restore supported only for the device owner");
- }
-
- long oldId = Binder.clearCallingIdentity();
-
- try {
- // Check whether the device has been provisioned -- we don't handle
- // full restores prior to completing the setup process.
- if (!deviceIsProvisioned()) {
- Slog.i(TAG, "Full restore not permitted before setup");
- return;
- }
-
- Slog.i(TAG, "Beginning restore...");
-
- AdbRestoreParams params = new AdbRestoreParams(fd);
- final int token = generateRandomIntegerToken();
- synchronized (mAdbBackupRestoreConfirmations) {
- mAdbBackupRestoreConfirmations.put(token, params);
- }
-
- // start up the confirmation UI
- if (DEBUG) Slog.d(TAG, "Starting restore confirmation UI, token=" + token);
- if (!startConfirmationUi(token, FullBackup.FULL_RESTORE_INTENT_ACTION)) {
- Slog.e(TAG, "Unable to launch restore confirmation");
- mAdbBackupRestoreConfirmations.delete(token);
- return;
- }
-
- // make sure the screen is lit for the user interaction
- mPowerManager.userActivity(SystemClock.uptimeMillis(),
- PowerManager.USER_ACTIVITY_EVENT_OTHER,
- 0);
-
- // start the confirmation countdown
- startConfirmationTimeout(token, params);
-
- // wait for the restore to be performed
- if (DEBUG) Slog.d(TAG, "Waiting for restore completion...");
- waitForCompletion(params);
- } finally {
- try {
- fd.close();
- } catch (IOException e) {
- Slog.w(TAG, "Error trying to close fd after adb restore: " + e);
- }
- Binder.restoreCallingIdentity(oldId);
- Slog.i(TAG, "adb restore processing complete.");
- }
- }
-
- boolean startConfirmationUi(int token, String action) {
- try {
- Intent confIntent = new Intent(action);
- confIntent.setClassName("com.android.backupconfirm",
- "com.android.backupconfirm.BackupRestoreConfirmation");
- confIntent.putExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, token);
- confIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivityAsUser(confIntent, UserHandle.SYSTEM);
- } catch (ActivityNotFoundException e) {
- return false;
- }
- return true;
- }
-
- void startConfirmationTimeout(int token, AdbParams params) {
- if (MORE_DEBUG) Slog.d(TAG, "Posting conf timeout msg after "
- + TIMEOUT_FULL_CONFIRMATION + " millis");
- Message msg = mBackupHandler.obtainMessage(MSG_FULL_CONFIRMATION_TIMEOUT,
- token, 0, params);
- mBackupHandler.sendMessageDelayed(msg, TIMEOUT_FULL_CONFIRMATION);
- }
-
- void waitForCompletion(AdbParams params) {
- synchronized (params.latch) {
- while (params.latch.get() == false) {
- try {
- params.latch.wait();
- } catch (InterruptedException e) { /* never interrupted */ }
- }
- }
- }
-
- void signalAdbBackupRestoreCompletion(AdbParams params) {
- synchronized (params.latch) {
- params.latch.set(true);
- params.latch.notifyAll();
- }
- }
-
- // Confirm that the previously-requested full backup/restore operation can proceed. This
- // is used to require a user-facing disclosure about the operation.
- @Override
- public void acknowledgeAdbBackupOrRestore(int token, boolean allow,
- String curPassword, String encPpassword, IFullBackupRestoreObserver observer) {
- if (DEBUG) Slog.d(TAG, "acknowledgeAdbBackupOrRestore : token=" + token
- + " allow=" + allow);
-
- // TODO: possibly require not just this signature-only permission, but even
- // require that the specific designated confirmation-UI app uid is the caller?
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "acknowledgeAdbBackupOrRestore");
-
- long oldId = Binder.clearCallingIdentity();
- try {
-
- AdbParams params;
- synchronized (mAdbBackupRestoreConfirmations) {
- params = mAdbBackupRestoreConfirmations.get(token);
- if (params != null) {
- mBackupHandler.removeMessages(MSG_FULL_CONFIRMATION_TIMEOUT, params);
- mAdbBackupRestoreConfirmations.delete(token);
-
- if (allow) {
- final int verb = params instanceof AdbBackupParams
- ? MSG_RUN_ADB_BACKUP
- : MSG_RUN_ADB_RESTORE;
-
- params.observer = observer;
- params.curPassword = curPassword;
-
- params.encryptPassword = encPpassword;
-
- if (MORE_DEBUG) Slog.d(TAG, "Sending conf message with verb " + verb);
- mWakelock.acquire();
- Message msg = mBackupHandler.obtainMessage(verb, params);
- mBackupHandler.sendMessage(msg);
- } else {
- Slog.w(TAG, "User rejected full backup/restore operation");
- // indicate completion without having actually transferred any data
- signalAdbBackupRestoreCompletion(params);
- }
- } else {
- Slog.w(TAG, "Attempted to ack full backup/restore with invalid token");
- }
- }
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
- }
-
- private static boolean backupSettingMigrated(int userId) {
- File base = new File(Environment.getDataDirectory(), "backup");
- File enableFile = new File(base, BACKUP_ENABLE_FILE);
- return enableFile.exists();
- }
-
- private static boolean readBackupEnableState(int userId) {
- File base = new File(Environment.getDataDirectory(), "backup");
- File enableFile = new File(base, BACKUP_ENABLE_FILE);
- if (enableFile.exists()) {
- try (FileInputStream fin = new FileInputStream(enableFile)) {
- int state = fin.read();
- return state != 0;
- } catch (IOException e) {
- // can't read the file; fall through to assume disabled
- Slog.e(TAG, "Cannot read enable state; assuming disabled");
- }
- } else {
- if (DEBUG) {
- Slog.i(TAG, "isBackupEnabled() => false due to absent settings file");
- }
- }
- return false;
- }
-
- private static void writeBackupEnableState(boolean enable, int userId) {
- File base = new File(Environment.getDataDirectory(), "backup");
- File enableFile = new File(base, BACKUP_ENABLE_FILE);
- File stage = new File(base, BACKUP_ENABLE_FILE + "-stage");
- FileOutputStream fout = null;
- try {
- fout = new FileOutputStream(stage);
- fout.write(enable ? 1 : 0);
- fout.close();
- stage.renameTo(enableFile);
- // will be synced immediately by the try-with-resources call to close()
- } catch (IOException|RuntimeException e) {
- // Whoops; looks like we're doomed. Roll everything out, disabled,
- // including the legacy state.
- Slog.e(TAG, "Unable to record backup enable state; reverting to disabled: "
- + e.getMessage());
-
- final ContentResolver r = sInstance.mContext.getContentResolver();
- Settings.Secure.putStringForUser(r,
- Settings.Secure.BACKUP_ENABLED, null, userId);
- enableFile.delete();
- stage.delete();
- } finally {
- IoUtils.closeQuietly(fout);
- }
- }
-
- // Enable/disable backups
- @Override
- public void setBackupEnabled(boolean enable) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "setBackupEnabled");
-
- Slog.i(TAG, "Backup enabled => " + enable);
-
- long oldId = Binder.clearCallingIdentity();
- try {
- boolean wasEnabled = mEnabled;
- synchronized (this) {
- writeBackupEnableState(enable, UserHandle.USER_SYSTEM);
- mEnabled = enable;
- }
-
- synchronized (mQueueLock) {
- if (enable && !wasEnabled && mProvisioned) {
- // if we've just been enabled, start scheduling backup passes
- KeyValueBackupJob.schedule(mContext, mConstants);
- scheduleNextFullBackupJob(0);
- } else if (!enable) {
- // No longer enabled, so stop running backups
- if (MORE_DEBUG) Slog.i(TAG, "Opting out of backup");
-
- KeyValueBackupJob.cancel(mContext);
-
- // This also constitutes an opt-out, so we wipe any data for
- // this device from the backend. We start that process with
- // an alarm in order to guarantee wakelock states.
- if (wasEnabled && mProvisioned) {
- // NOTE: we currently flush every registered transport, not just
- // the currently-active one.
- String[] allTransports = mTransportManager.getBoundTransportNames();
- // build the set of transports for which we are posting an init
- for (String transport : allTransports) {
- recordInitPendingLocked(true, transport);
- }
- mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
- mRunInitIntent);
- }
- }
- }
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
- }
-
- // Enable/disable automatic restore of app data at install time
- @Override
- public void setAutoRestore(boolean doAutoRestore) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "setAutoRestore");
-
- Slog.i(TAG, "Auto restore => " + doAutoRestore);
-
- final long oldId = Binder.clearCallingIdentity();
- try {
- synchronized (this) {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0);
- mAutoRestore = doAutoRestore;
- }
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
- }
-
- // Mark the backup service as having been provisioned
- @Override
- public void setBackupProvisioned(boolean available) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "setBackupProvisioned");
- /*
- * This is now a no-op; provisioning is simply the device's own setup state.
- */
- }
-
- // Report whether the backup mechanism is currently enabled
- @Override
- public boolean isBackupEnabled() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "isBackupEnabled");
- return mEnabled; // no need to synchronize just to read it
- }
-
- // Report the name of the currently active transport
- @Override
- public String getCurrentTransport() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "getCurrentTransport");
- String currentTransport = mTransportManager.getCurrentTransportName();
- if (MORE_DEBUG) Slog.v(TAG, "... getCurrentTransport() returning " + currentTransport);
- return currentTransport;
- }
-
- // Report all known, available backup transports
- @Override
- public String[] listAllTransports() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "listAllTransports");
-
- return mTransportManager.getBoundTransportNames();
- }
-
- @Override
- public ComponentName[] listAllTransportComponents() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "listAllTransportComponents");
- return mTransportManager.getAllTransportComponents();
- }
-
- @Override
- public String[] getTransportWhitelist() {
- // No permission check, intentionally.
- Set<ComponentName> whitelistedComponents = mTransportManager.getTransportWhitelist();
- String[] whitelistedTransports = new String[whitelistedComponents.size()];
- int i = 0;
- for (ComponentName component : whitelistedComponents) {
- whitelistedTransports[i] = component.flattenToShortString();
- i++;
- }
- return whitelistedTransports;
- }
-
- // Select which transport to use for the next backup operation.
- @Override
- public String selectBackupTransport(String transport) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "selectBackupTransport");
-
- final long oldId = Binder.clearCallingIdentity();
- try {
- String prevTransport = mTransportManager.selectTransport(transport);
- updateStateForTransport(transport);
- Slog.v(TAG, "selectBackupTransport() set " + mTransportManager.getCurrentTransportName()
- + " returning " + prevTransport);
- return prevTransport;
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
- }
-
- @Override
- public void selectBackupTransportAsync(final ComponentName transport,
- final ISelectBackupTransportCallback listener) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "selectBackupTransportAsync");
-
- final long oldId = Binder.clearCallingIdentity();
-
- Slog.v(TAG, "selectBackupTransportAsync() called with transport " +
- transport.flattenToShortString());
-
- mTransportManager.ensureTransportReady(transport, new TransportManager.TransportReadyCallback() {
- @Override
- public void onSuccess(String transportName) {
- mTransportManager.selectTransport(transportName);
- updateStateForTransport(mTransportManager.getCurrentTransportName());
- Slog.v(TAG, "Transport successfully selected: " + transport.flattenToShortString());
- try {
- listener.onSuccess(transportName);
- } catch (RemoteException e) {
- // Nothing to do here.
- }
- }
-
- @Override
- public void onFailure(int reason) {
- Slog.v(TAG, "Failed to select transport: " + transport.flattenToShortString());
- try {
- listener.onFailure(reason);
- } catch (RemoteException e) {
- // Nothing to do here.
- }
- }
- });
-
- Binder.restoreCallingIdentity(oldId);
- }
-
- private void updateStateForTransport(String newTransportName) {
- // Publish the name change
- Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.BACKUP_TRANSPORT, newTransportName);
-
- // And update our current-dataset bookkeeping
- IBackupTransport transport = mTransportManager.getTransportBinder(newTransportName);
- if (transport != null) {
- try {
- mCurrentToken = transport.getCurrentRestoreSet();
- } catch (Exception e) {
- // Oops. We can't know the current dataset token, so reset and figure it out
- // when we do the next k/v backup operation on this transport.
- mCurrentToken = 0;
- }
- } else {
- // The named transport isn't bound at this particular moment, so we can't
- // know yet what its current dataset token is. Reset as above.
- mCurrentToken = 0;
- }
- }
-
- // 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 returns null.
- @Override
- public Intent getConfigurationIntent(String transportName) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "getConfigurationIntent");
-
- final IBackupTransport transport = mTransportManager.getTransportBinder(transportName);
- if (transport != null) {
- try {
- final Intent intent = transport.configurationIntent();
- if (MORE_DEBUG) Slog.d(TAG, "getConfigurationIntent() returning config intent "
- + intent);
- return intent;
- } catch (Exception e) {
- /* fall through to return null */
- Slog.e(TAG, "Unable to get configuration intent from transport: " + e.getMessage());
- }
- }
-
- return null;
- }
-
- // Supply the configuration summary string for the given transport. If the name is
- // not one of the available transports, or if the transport does not supply any
- // summary / destination string, the method can return null.
- //
- // This string is used VERBATIM as the summary text of the relevant Settings item!
- @Override
- public String getDestinationString(String transportName) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "getDestinationString");
-
- final IBackupTransport transport = mTransportManager.getTransportBinder(transportName);
- if (transport != null) {
- try {
- final String text = transport.currentDestinationString();
- if (MORE_DEBUG) Slog.d(TAG, "getDestinationString() returning " + text);
- return text;
- } catch (Exception e) {
- /* fall through to return null */
- Slog.e(TAG, "Unable to get string from transport: " + e.getMessage());
- }
- }
-
- return null;
- }
-
- // Supply the manage-data intent for the given transport.
- @Override
- public Intent getDataManagementIntent(String transportName) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "getDataManagementIntent");
-
- final IBackupTransport transport = mTransportManager.getTransportBinder(transportName);
- if (transport != null) {
- try {
- final Intent intent = transport.dataManagementIntent();
- if (MORE_DEBUG) Slog.d(TAG, "getDataManagementIntent() returning intent "
- + intent);
- return intent;
- } catch (Exception e) {
- /* fall through to return null */
- Slog.e(TAG, "Unable to get management intent from transport: " + e.getMessage());
- }
- }
-
- return null;
- }
-
- // Supply the menu label for affordances that fire the manage-data intent
- // for the given transport.
- @Override
- public String getDataManagementLabel(String transportName) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "getDataManagementLabel");
-
- final IBackupTransport transport = mTransportManager.getTransportBinder(transportName);
- if (transport != null) {
- try {
- final String text = transport.dataManagementLabel();
- if (MORE_DEBUG) Slog.d(TAG, "getDataManagementLabel() returning " + text);
- return text;
- } catch (Exception e) {
- /* fall through to return null */
- Slog.e(TAG, "Unable to get management label from transport: " + e.getMessage());
- }
- }
-
- return null;
- }
-
- // Callback: a requested backup agent has been instantiated. This should only
- // be called from the Activity Manager.
- @Override
- public void agentConnected(String packageName, IBinder agentBinder) {
- synchronized(mAgentConnectLock) {
- if (Binder.getCallingUid() == Process.SYSTEM_UID) {
- Slog.d(TAG, "agentConnected pkg=" + packageName + " agent=" + agentBinder);
- IBackupAgent agent = IBackupAgent.Stub.asInterface(agentBinder);
- mConnectedAgent = agent;
- mConnecting = false;
- } else {
- Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
- + " claiming agent connected");
- }
- mAgentConnectLock.notifyAll();
- }
- }
-
- // Callback: a backup agent has failed to come up, or has unexpectedly quit.
- // If the agent failed to come up in the first place, the agentBinder argument
- // will be null. This should only be called from the Activity Manager.
- @Override
- public void agentDisconnected(String packageName) {
- // TODO: handle backup being interrupted
- synchronized(mAgentConnectLock) {
- if (Binder.getCallingUid() == Process.SYSTEM_UID) {
- mConnectedAgent = null;
- mConnecting = false;
- } else {
- Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
- + " claiming agent disconnected");
- }
- mAgentConnectLock.notifyAll();
- }
- }
-
- // An application being installed will need a restore pass, then the Package Manager
- // will need to be told when the restore is finished.
- @Override
- public void restoreAtInstall(String packageName, int token) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
- + " attemping install-time restore");
- return;
- }
-
- boolean skip = false;
-
- long restoreSet = getAvailableRestoreToken(packageName);
- if (DEBUG) Slog.v(TAG, "restoreAtInstall pkg=" + packageName
- + " token=" + Integer.toHexString(token)
- + " restoreSet=" + Long.toHexString(restoreSet));
- if (restoreSet == 0) {
- if (MORE_DEBUG) Slog.i(TAG, "No restore set");
- skip = true;
- }
-
- // Do we have a transport to fetch data for us?
- IBackupTransport transport = mTransportManager.getCurrentTransportBinder();
- if (transport == null) {
- if (DEBUG) Slog.w(TAG, "No transport");
- skip = true;
- }
-
- if (!mAutoRestore) {
- if (DEBUG) {
- Slog.w(TAG, "Non-restorable state: auto=" + mAutoRestore);
- }
- skip = true;
- }
-
- if (!skip) {
- try {
- // okay, we're going to attempt a restore of this package from this restore set.
- // The eventual message back into the Package Manager to run the post-install
- // steps for 'token' will be issued from the restore handling code.
-
- // This can throw and so *must* happen before the wakelock is acquired
- String dirName = transport.transportDirName();
-
- mWakelock.acquire();
- if (MORE_DEBUG) {
- Slog.d(TAG, "Restore at install of " + packageName);
- }
- Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(transport, dirName, null, null,
- restoreSet, packageName, token);
- mBackupHandler.sendMessage(msg);
- } catch (Exception e) {
- // Calling into the transport broke; back off and proceed with the installation.
- Slog.e(TAG, "Unable to contact transport: " + e.getMessage());
- skip = true;
- }
- }
-
- if (skip) {
- // Auto-restore disabled or no way to attempt a restore; just tell the Package
- // Manager to proceed with the post-install handling for this package.
- if (DEBUG) Slog.v(TAG, "Finishing install immediately");
- try {
- mPackageManagerBinder.finishPackageInstall(token, false);
- } catch (RemoteException e) { /* can't happen */ }
- }
- }
-
- // Hand off a restore session
- @Override
- public IRestoreSession beginRestoreSession(String packageName, String transport) {
- if (DEBUG) Slog.v(TAG, "beginRestoreSession: pkg=" + packageName
- + " transport=" + transport);
-
- boolean needPermission = true;
- if (transport == null) {
- transport = mTransportManager.getCurrentTransportName();
-
- if (packageName != null) {
- PackageInfo app = null;
- try {
- app = mPackageManager.getPackageInfo(packageName, 0);
- } catch (NameNotFoundException nnf) {
- Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
- throw new IllegalArgumentException("Package " + packageName + " not found");
- }
-
- if (app.applicationInfo.uid == Binder.getCallingUid()) {
- // So: using the current active transport, and the caller has asked
- // that its own package will be restored. In this narrow use case
- // we do not require the caller to hold the permission.
- needPermission = false;
- }
- }
- }
-
- if (needPermission) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "beginRestoreSession");
- } else {
- if (DEBUG) Slog.d(TAG, "restoring self on current transport; no permission needed");
- }
-
- synchronized(this) {
- if (mActiveRestoreSession != null) {
- Slog.i(TAG, "Restore session requested but one already active");
- return null;
- }
- if (mBackupRunning) {
- Slog.i(TAG, "Restore session requested but currently running backups");
- return null;
- }
- mActiveRestoreSession = new ActiveRestoreSession(packageName, transport);
- mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT,
- TIMEOUT_RESTORE_INTERVAL);
- }
- return mActiveRestoreSession;
- }
-
- void clearRestoreSession(ActiveRestoreSession currentSession) {
- synchronized(this) {
- if (currentSession != mActiveRestoreSession) {
- Slog.e(TAG, "ending non-current restore session");
- } else {
- if (DEBUG) Slog.v(TAG, "Clearing restore session and halting timeout");
- mActiveRestoreSession = null;
- mBackupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
- }
- }
- }
-
- // Note that a currently-active backup agent has notified us that it has
- // completed the given outstanding asynchronous backup/restore operation.
- @Override
- public void opComplete(int token, long result) {
- if (MORE_DEBUG) {
- Slog.v(TAG, "opComplete: " + Integer.toHexString(token) + " result=" + result);
- }
- Operation op = null;
- synchronized (mCurrentOpLock) {
- op = mCurrentOperations.get(token);
- if (op != null) {
- if (op.state == OP_TIMEOUT) {
- // The operation already timed out, and this is a late response. Tidy up
- // and ignore it; we've already dealt with the timeout.
- op = null;
- mCurrentOperations.delete(token);
- } else if (op.state == OP_ACKNOWLEDGED) {
- if (DEBUG) {
- Slog.w(TAG, "Received duplicate ack for token=" +
- Integer.toHexString(token));
- }
- op = null;
- mCurrentOperations.remove(token);
- } else if (op.state == OP_PENDING) {
- // Can't delete op from mCurrentOperations. waitUntilOperationComplete can be
- // called after we we receive this call.
- op.state = OP_ACKNOWLEDGED;
- }
- }
- mCurrentOpLock.notifyAll();
- }
-
- // The completion callback, if any, is invoked on the handler
- if (op != null && op.callback != null) {
- Pair<BackupRestoreTask, Long> callbackAndResult = Pair.create(op.callback, result);
- Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, callbackAndResult);
- mBackupHandler.sendMessage(msg);
- }
- }
-
- @Override
- public boolean isAppEligibleForBackup(String packageName) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "isAppEligibleForBackup");
- try {
- PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
- PackageManager.GET_SIGNATURES);
- if (!appIsEligibleForBackup(packageInfo.applicationInfo, mPackageManager) ||
- appIsStopped(packageInfo.applicationInfo)) {
- return false;
- }
- IBackupTransport transport = mTransportManager.getCurrentTransportBinder();
- if (transport != null) {
- try {
- return transport.isAppEligibleForBackup(packageInfo,
- appGetsFullBackup(packageInfo));
- } catch (Exception e) {
- Slog.e(TAG, "Unable to ask about eligibility: " + e.getMessage());
- }
- }
- // If transport is not present we couldn't tell that the package is not eligible.
- return true;
- } catch (NameNotFoundException e) {
- return false;
- }
- }
-
- // ----- Restore session -----
-
- class ActiveRestoreSession extends IRestoreSession.Stub {
- private static final String TAG = "RestoreSession";
-
- private String mPackageName;
- private IBackupTransport mRestoreTransport = null;
- RestoreSet[] mRestoreSets = null;
- boolean mEnded = false;
- boolean mTimedOut = false;
-
- ActiveRestoreSession(String packageName, String transport) {
- mPackageName = packageName;
- mRestoreTransport = mTransportManager.getTransportBinder(transport);
- }
-
- public void markTimedOut() {
- mTimedOut = true;
- }
-
- // --- Binder interface ---
- public synchronized int getAvailableRestoreSets(IRestoreObserver observer,
- IBackupManagerMonitor monitor) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "getAvailableRestoreSets");
- if (observer == null) {
- throw new IllegalArgumentException("Observer must not be null");
- }
-
- if (mEnded) {
- throw new IllegalStateException("Restore session already ended");
- }
-
- if (mTimedOut) {
- Slog.i(TAG, "Session already timed out");
- return -1;
- }
-
- long oldId = Binder.clearCallingIdentity();
- try {
- if (mRestoreTransport == null) {
- Slog.w(TAG, "Null transport getting restore sets");
- return -1;
- }
-
- // We know we're doing legit work now, so halt the timeout
- // until we're done. It gets started again when the result
- // comes in.
- mBackupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
-
- // spin off the transport request to our service thread
- mWakelock.acquire();
- Message msg = mBackupHandler.obtainMessage(MSG_RUN_GET_RESTORE_SETS,
- new RestoreGetSetsParams(mRestoreTransport, this, observer,
- monitor));
- mBackupHandler.sendMessage(msg);
- return 0;
- } catch (Exception e) {
- Slog.e(TAG, "Error in getAvailableRestoreSets", e);
- return -1;
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
- }
-
- public synchronized int restoreAll(long token, IRestoreObserver observer,
- IBackupManagerMonitor monitor) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "performRestore");
-
- if (DEBUG) Slog.d(TAG, "restoreAll token=" + Long.toHexString(token)
- + " observer=" + observer);
-
- if (mEnded) {
- throw new IllegalStateException("Restore session already ended");
- }
-
- if (mTimedOut) {
- Slog.i(TAG, "Session already timed out");
- return -1;
- }
-
- if (mRestoreTransport == null || mRestoreSets == null) {
- Slog.e(TAG, "Ignoring restoreAll() with no restore set");
- return -1;
- }
-
- if (mPackageName != null) {
- Slog.e(TAG, "Ignoring restoreAll() on single-package session");
- return -1;
- }
-
- String dirName;
- try {
- dirName = mRestoreTransport.transportDirName();
- } catch (Exception e) {
- // Transport went AWOL; fail.
- Slog.e(TAG, "Unable to get transport dir for restore: " + e.getMessage());
- return -1;
- }
-
- synchronized (mQueueLock) {
- for (int i = 0; i < mRestoreSets.length; i++) {
- if (token == mRestoreSets[i].token) {
- // Real work, so stop the session timeout until we finalize the restore
- mBackupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
-
- long oldId = Binder.clearCallingIdentity();
- mWakelock.acquire();
- if (MORE_DEBUG) {
- Slog.d(TAG, "restoreAll() kicking off");
- }
- Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, dirName,
- observer, monitor, token);
- mBackupHandler.sendMessage(msg);
- Binder.restoreCallingIdentity(oldId);
- return 0;
- }
- }
- }
-
- Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
- return -1;
- }
-
- // Restores of more than a single package are treated as 'system' restores
- public synchronized int restoreSome(long token, IRestoreObserver observer,
- IBackupManagerMonitor monitor, String[] packages) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "performRestore");
-
- if (DEBUG) {
- StringBuilder b = new StringBuilder(128);
- b.append("restoreSome token=");
- b.append(Long.toHexString(token));
- b.append(" observer=");
- b.append(observer.toString());
- b.append(" monitor=");
- if (monitor == null) {
- b.append("null");
- } else {
- b.append(monitor.toString());
- }
- b.append(" packages=");
- if (packages == null) {
- b.append("null");
- } else {
- b.append('{');
- boolean first = true;
- for (String s : packages) {
- if (!first) {
- b.append(", ");
- } else first = false;
- b.append(s);
- }
- b.append('}');
- }
- Slog.d(TAG, b.toString());
- }
-
- if (mEnded) {
- throw new IllegalStateException("Restore session already ended");
- }
-
- if (mTimedOut) {
- Slog.i(TAG, "Session already timed out");
- return -1;
- }
-
- if (mRestoreTransport == null || mRestoreSets == null) {
- Slog.e(TAG, "Ignoring restoreAll() with no restore set");
- return -1;
- }
-
- if (mPackageName != null) {
- Slog.e(TAG, "Ignoring restoreAll() on single-package session");
- return -1;
- }
-
- String dirName;
- try {
- dirName = mRestoreTransport.transportDirName();
- } catch (Exception e) {
- // Transport went AWOL; fail.
- Slog.e(TAG, "Unable to get transport name for restoreSome: " + e.getMessage());
- return -1;
- }
-
- synchronized (mQueueLock) {
- for (int i = 0; i < mRestoreSets.length; i++) {
- if (token == mRestoreSets[i].token) {
- // Stop the session timeout until we finalize the restore
- mBackupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
-
- long oldId = Binder.clearCallingIdentity();
- mWakelock.acquire();
- if (MORE_DEBUG) {
- Slog.d(TAG, "restoreSome() of " + packages.length + " packages");
- }
- Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, monitor,
- token, packages, packages.length > 1);
- mBackupHandler.sendMessage(msg);
- Binder.restoreCallingIdentity(oldId);
- return 0;
- }
- }
- }
-
- Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
- return -1;
- }
-
- public synchronized int restorePackage(String packageName, IRestoreObserver observer,
- IBackupManagerMonitor monitor) {
- if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName + " obs=" + observer
- + "monitor=" + monitor);
-
- if (mEnded) {
- throw new IllegalStateException("Restore session already ended");
- }
-
- if (mTimedOut) {
- Slog.i(TAG, "Session already timed out");
- return -1;
- }
-
- if (mPackageName != null) {
- if (! mPackageName.equals(packageName)) {
- Slog.e(TAG, "Ignoring attempt to restore pkg=" + packageName
- + " on session for package " + mPackageName);
- return -1;
- }
- }
-
- PackageInfo app = null;
- try {
- app = mPackageManager.getPackageInfo(packageName, 0);
- } catch (NameNotFoundException nnf) {
- Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
- return -1;
- }
-
- // If the caller is not privileged and is not coming from the target
- // app's uid, throw a permission exception back to the caller.
- int perm = mContext.checkPermission(android.Manifest.permission.BACKUP,
- Binder.getCallingPid(), Binder.getCallingUid());
- if ((perm == PackageManager.PERMISSION_DENIED) &&
- (app.applicationInfo.uid != Binder.getCallingUid())) {
- Slog.w(TAG, "restorePackage: bad packageName=" + packageName
- + " or calling uid=" + Binder.getCallingUid());
- throw new SecurityException("No permission to restore other packages");
- }
-
- // So far so good; we're allowed to try to restore this package.
- long oldId = Binder.clearCallingIdentity();
- try {
- // Check whether there is data for it in the current dataset, falling back
- // to the ancestral dataset if not.
- long token = getAvailableRestoreToken(packageName);
- if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName
- + " token=" + Long.toHexString(token));
-
- // If we didn't come up with a place to look -- no ancestral dataset and
- // the app has never been backed up from this device -- there's nothing
- // to do but return failure.
- if (token == 0) {
- if (DEBUG) Slog.w(TAG, "No data available for this package; not restoring");
- return -1;
- }
-
- String dirName;
- try {
- dirName = mRestoreTransport.transportDirName();
- } catch (Exception e) {
- // Transport went AWOL; fail.
- Slog.e(TAG, "Unable to get transport dir for restorePackage: " + e.getMessage());
- return -1;
- }
-
- // Stop the session timeout until we finalize the restore
- mBackupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
-
- // Ready to go: enqueue the restore request and claim success
- mWakelock.acquire();
- if (MORE_DEBUG) {
- Slog.d(TAG, "restorePackage() : " + packageName);
- }
- Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, monitor,
- token, app);
- mBackupHandler.sendMessage(msg);
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
- return 0;
- }
-
- // Posted to the handler to tear down a restore session in a cleanly synchronized way
- class EndRestoreRunnable implements Runnable {
- BackupManagerService mBackupManager;
- ActiveRestoreSession mSession;
-
- EndRestoreRunnable(BackupManagerService manager, ActiveRestoreSession session) {
- mBackupManager = manager;
- mSession = session;
- }
-
- public void run() {
- // clean up the session's bookkeeping
- synchronized (mSession) {
- mSession.mRestoreTransport = null;
- mSession.mEnded = true;
- }
-
- // clean up the BackupManagerImpl side of the bookkeeping
- // and cancel any pending timeout message
- mBackupManager.clearRestoreSession(mSession);
- }
- }
-
- public synchronized void endRestoreSession() {
- if (DEBUG) Slog.d(TAG, "endRestoreSession");
-
- if (mTimedOut) {
- Slog.i(TAG, "Session already timed out");
- return;
- }
-
- if (mEnded) {
- throw new IllegalStateException("Restore session already ended");
- }
-
- mBackupHandler.post(new EndRestoreRunnable(BackupManagerService.this, this));
- }
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
-
- long identityToken = Binder.clearCallingIdentity();
- try {
- if (args != null) {
- for (String arg : args) {
- if ("-h".equals(arg)) {
- pw.println("'dumpsys backup' optional arguments:");
- pw.println(" -h : this help text");
- pw.println(" a[gents] : dump information about defined backup agents");
- return;
- } else if ("agents".startsWith(arg)) {
- dumpAgents(pw);
- return;
- }
- }
- }
- dumpInternal(pw);
- } finally {
- Binder.restoreCallingIdentity(identityToken);
- }
- }
-
- private void dumpAgents(PrintWriter pw) {
- List<PackageInfo> agentPackages = allAgentPackages();
- pw.println("Defined backup agents:");
- for (PackageInfo pkg : agentPackages) {
- pw.print(" ");
- pw.print(pkg.packageName); pw.println(':');
- pw.print(" "); pw.println(pkg.applicationInfo.backupAgentName);
- }
- }
-
- private void dumpInternal(PrintWriter pw) {
- synchronized (mQueueLock) {
- pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled")
- + " / " + (!mProvisioned ? "not " : "") + "provisioned / "
- + (this.mPendingInits.size() == 0 ? "not " : "") + "pending init");
- pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled"));
- if (mBackupRunning) pw.println("Backup currently running");
- pw.println("Last backup pass started: " + mLastBackupPass
- + " (now = " + System.currentTimeMillis() + ')');
- pw.println(" next scheduled: " + KeyValueBackupJob.nextScheduled());
-
- pw.println("Transport whitelist:");
- for (ComponentName transport : mTransportManager.getTransportWhitelist()) {
- pw.print(" ");
- pw.println(transport.flattenToShortString());
- }
-
- pw.println("Available transports:");
- final String[] transports = listAllTransports();
- if (transports != null) {
- for (String t : listAllTransports()) {
- pw.println((t.equals(mTransportManager.getCurrentTransportName()) ? " * " : " ") + t);
- try {
- IBackupTransport transport = mTransportManager.getTransportBinder(t);
- File dir = new File(mBaseStateDir, transport.transportDirName());
- pw.println(" destination: " + transport.currentDestinationString());
- pw.println(" intent: " + transport.configurationIntent());
- for (File f : dir.listFiles()) {
- pw.println(" " + f.getName() + " - " + f.length() + " state bytes");
- }
- } catch (Exception e) {
- Slog.e(TAG, "Error in transport", e);
- pw.println(" Error: " + e);
- }
- }
- }
-
- pw.println("Pending init: " + mPendingInits.size());
- for (String s : mPendingInits) {
- pw.println(" " + s);
- }
-
- if (DEBUG_BACKUP_TRACE) {
- synchronized (mBackupTrace) {
- if (!mBackupTrace.isEmpty()) {
- pw.println("Most recent backup trace:");
- for (String s : mBackupTrace) {
- pw.println(" " + s);
- }
- }
- }
- }
-
- pw.print("Ancestral: "); pw.println(Long.toHexString(mAncestralToken));
- pw.print("Current: "); pw.println(Long.toHexString(mCurrentToken));
-
- int N = mBackupParticipants.size();
- pw.println("Participants:");
- for (int i=0; i<N; i++) {
- int uid = mBackupParticipants.keyAt(i);
- pw.print(" uid: ");
- pw.println(uid);
- HashSet<String> participants = mBackupParticipants.valueAt(i);
- for (String app: participants) {
- pw.println(" " + app);
- }
- }
-
- pw.println("Ancestral packages: "
- + (mAncestralPackages == null ? "none" : mAncestralPackages.size()));
- if (mAncestralPackages != null) {
- for (String pkg : mAncestralPackages) {
- pw.println(" " + pkg);
- }
- }
-
- pw.println("Ever backed up: " + mEverStoredApps.size());
- for (String pkg : mEverStoredApps) {
- pw.println(" " + pkg);
- }
-
- pw.println("Pending key/value backup: " + mPendingBackups.size());
- for (BackupRequest req : mPendingBackups.values()) {
- pw.println(" " + req);
- }
-
- pw.println("Full backup queue:" + mFullBackupQueue.size());
- for (FullBackupEntry entry : mFullBackupQueue) {
- pw.print(" "); pw.print(entry.lastBackup);
- pw.print(" : "); pw.println(entry.packageName);
- }
- }
- }
-
- private static void sendBackupOnUpdate(IBackupObserver observer, String packageName,
- BackupProgress progress) {
- if (observer != null) {
- try {
- observer.onUpdate(packageName, progress);
- } catch (RemoteException e) {
- if (DEBUG) {
- Slog.w(TAG, "Backup observer went away: onUpdate");
- }
- }
- }
- }
-
- private static void sendBackupOnPackageResult(IBackupObserver observer, String packageName,
- int status) {
- if (observer != null) {
- try {
- observer.onResult(packageName, status);
- } catch (RemoteException e) {
- if (DEBUG) {
- Slog.w(TAG, "Backup observer went away: onResult");
- }
- }
- }
- }
-
- private static void sendBackupFinished(IBackupObserver observer, int status) {
- if (observer != null) {
- try {
- observer.backupFinished(status);
- } catch (RemoteException e) {
- if (DEBUG) {
- Slog.w(TAG, "Backup observer went away: backupFinished");
- }
- }
- }
- }
-
- private Bundle putMonitoringExtra(Bundle extras, String key, String value) {
- if (extras == null) {
- extras = new Bundle();
- }
- extras.putString(key, value);
- return extras;
- }
-
- private Bundle putMonitoringExtra(Bundle extras, String key, int value) {
- if (extras == null) {
- extras = new Bundle();
- }
- extras.putInt(key, value);
- return extras;
- }
-
- private Bundle putMonitoringExtra(Bundle extras, String key, long value) {
- if (extras == null) {
- extras = new Bundle();
- }
- extras.putLong(key, value);
- return extras;
- }
-
-
- private Bundle putMonitoringExtra(Bundle extras, String key, boolean value) {
- if (extras == null) {
- extras = new Bundle();
- }
- extras.putBoolean(key, value);
- return extras;
- }
-
- private static IBackupManagerMonitor monitorEvent(IBackupManagerMonitor monitor, int id,
- PackageInfo pkg, int category, Bundle extras) {
- if (monitor != null) {
- try {
- Bundle bundle = new Bundle();
- bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID, id);
- bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_CATEGORY, category);
- if (pkg != null) {
- bundle.putString(EXTRA_LOG_EVENT_PACKAGE_NAME,
- pkg.packageName);
- bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION,
- pkg.versionCode);
- }
- if (extras != null) {
- bundle.putAll(extras);
- }
- monitor.onEvent(bundle);
- return monitor;
- } catch(RemoteException e) {
- if (DEBUG) {
- Slog.w(TAG, "backup manager monitor went away");
- }
- }
- }
- return null;
- }
-
- @Override
- public IBackupManager getBackupManagerBinder() {
- return mBackupManagerBinder;
- }
-
-}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java b/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java
index 041f9ed..86462d8 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java
@@ -120,6 +120,15 @@
// Report whether the backup mechanism is currently enabled
boolean isBackupEnabled();
+ // Update the transport attributes
+ void updateTransportAttributes(
+ ComponentName transportComponent,
+ String name,
+ Intent configurationIntent,
+ String currentDestinationString,
+ Intent dataManagementIntent,
+ String dataManagementLabel);
+
// Report the name of the currently active transport
String getCurrentTransport();
diff --git a/services/backup/java/com/android/server/backup/FileMetadata.java b/services/backup/java/com/android/server/backup/FileMetadata.java
index 5465609..3d260cb 100644
--- a/services/backup/java/com/android/server/backup/FileMetadata.java
+++ b/services/backup/java/com/android/server/backup/FileMetadata.java
@@ -36,7 +36,7 @@
public long mode; // e.g. 0666 (actually int)
public long mtime; // last mod time, UTC time_t (actually int)
public long size; // bytes of content
- public int version; // App version.
+ public long version; // App version.
public boolean hasApk; // Whether backup file contains apk.
@Override
diff --git a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
index f658f22..2d2993d 100644
--- a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -99,10 +99,10 @@
// For compactness we store the SHA-256 hash of each app's Signatures
// rather than the Signature blocks themselves.
public class Metadata {
- public int versionCode;
+ public long versionCode;
public ArrayList<byte[]> sigHashes;
- Metadata(int version, ArrayList<byte[]> hashes) {
+ Metadata(long version, ArrayList<byte[]> hashes) {
versionCode = version;
sigHashes = hashes;
}
@@ -206,7 +206,7 @@
homeInfo = mPackageManager.getPackageInfo(home.getPackageName(),
PackageManager.GET_SIGNATURES);
homeInstaller = mPackageManager.getInstallerPackageName(home.getPackageName());
- homeVersion = homeInfo.versionCode;
+ homeVersion = homeInfo.getLongVersionCode();
homeSigHashes = BackupUtils.hashSignatureArray(homeInfo.signatures);
} catch (NameNotFoundException e) {
Slog.w(TAG, "Can't access preferred home info");
@@ -287,7 +287,7 @@
// metadata again. In either case, take it out of mExisting so that
// we don't consider it deleted later.
mExisting.remove(packName);
- if (info.versionCode == mStateVersions.get(packName).versionCode) {
+ if (info.getLongVersionCode() == mStateVersions.get(packName).versionCode) {
continue;
}
}
@@ -309,13 +309,18 @@
// marshal the version code in a canonical form
outputBuffer.reset();
- outputBufferStream.writeInt(info.versionCode);
+ if (info.versionCodeMajor != 0) {
+ outputBufferStream.writeInt(Integer.MIN_VALUE);
+ outputBufferStream.writeLong(info.getLongVersionCode());
+ } else {
+ outputBufferStream.writeInt(info.versionCode);
+ }
writeSignatureHashArray(outputBufferStream,
BackupUtils.hashSignatureArray(info.signatures));
if (DEBUG) {
Slog.v(TAG, "+ writing metadata for " + packName
- + " version=" + info.versionCode
+ + " version=" + info.getLongVersionCode()
+ " entityLen=" + outputBuffer.size());
}
@@ -409,7 +414,13 @@
}
} else {
// it's a file metadata record
- int versionCode = inputBufferStream.readInt();
+ int versionCodeInt = inputBufferStream.readInt();
+ long versionCode;
+ if (versionCodeInt == Integer.MIN_VALUE) {
+ versionCode = inputBufferStream.readLong();
+ } else {
+ versionCode = versionCodeInt;
+ }
ArrayList<byte[]> sigs = readSignatureHashArray(inputBufferStream);
if (DEBUG) {
Slog.i(TAG, " read metadata for " + key
@@ -561,7 +572,13 @@
// The global metadata was last; now read all the apps
while (true) {
pkg = in.readUTF();
- int versionCode = in.readInt();
+ int versionCodeInt = in.readInt();
+ long versionCode;
+ if (versionCodeInt == Integer.MIN_VALUE) {
+ versionCode = in.readLong();
+ } else {
+ versionCode = versionCodeInt;
+ }
if (!ignoreExisting) {
mExisting.add(pkg);
@@ -609,7 +626,12 @@
// now write all the app names + versions
for (PackageInfo pkg : pkgs) {
out.writeUTF(pkg.packageName);
- out.writeInt(pkg.versionCode);
+ if (pkg.versionCodeMajor != 0) {
+ out.writeInt(Integer.MIN_VALUE);
+ out.writeLong(pkg.getLongVersionCode());
+ } else {
+ out.writeInt(pkg.versionCode);
+ }
}
out.flush();
diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
index 2788218..bd0d853 100644
--- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
@@ -91,8 +91,10 @@
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.backup.IBackupTransport;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
import com.android.server.AppWidgetBackupBridge;
import com.android.server.EventLogTags;
import com.android.server.SystemConfig;
@@ -723,8 +725,54 @@
// ----- Main service implementation -----
- public RefactoredBackupManagerService(Context context, Trampoline parent,
+ public static RefactoredBackupManagerService create(
+ Context context,
+ Trampoline parent,
HandlerThread backupThread) {
+ // Set up our transport options and initialize the default transport
+ SystemConfig systemConfig = SystemConfig.getInstance();
+ Set<ComponentName> transportWhitelist = systemConfig.getBackupTransportWhitelist();
+
+ String transport =
+ Settings.Secure.getString(
+ context.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT);
+ if (TextUtils.isEmpty(transport)) {
+ transport = null;
+ }
+ if (DEBUG) {
+ Slog.v(TAG, "Starting with transport " + transport);
+ }
+ TransportManager transportManager =
+ new TransportManager(
+ context,
+ transportWhitelist,
+ transport,
+ backupThread.getLooper());
+
+ // If encrypted file systems is enabled or disabled, this call will return the
+ // correct directory.
+ File baseStateDir = new File(Environment.getDataDirectory(), "backup");
+
+ // This dir on /cache is managed directly in init.rc
+ File dataDir = new File(Environment.getDownloadCacheDirectory(), "backup_stage");
+
+ return new RefactoredBackupManagerService(
+ context,
+ parent,
+ backupThread,
+ baseStateDir,
+ dataDir,
+ transportManager);
+ }
+
+ @VisibleForTesting
+ RefactoredBackupManagerService(
+ Context context,
+ Trampoline parent,
+ HandlerThread backupThread,
+ File baseStateDir,
+ File dataDir,
+ TransportManager transportManager) {
mContext = context;
mPackageManager = context.getPackageManager();
mPackageManagerBinder = AppGlobals.getPackageManager();
@@ -751,16 +799,13 @@
Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
false, mProvisionedObserver);
- // If Encrypted file systems is enabled or disabled, this call will return the
- // correct directory.
- mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
+ mBaseStateDir = baseStateDir;
mBaseStateDir.mkdirs();
if (!SELinux.restorecon(mBaseStateDir)) {
Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir);
}
- // This dir on /cache is managed directly in init.rc
- mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup_stage");
+ mDataDir = dataDir;
mBackupPasswordManager = new BackupPasswordManager(mContext, mBaseStateDir, mRng);
@@ -803,26 +848,13 @@
addPackageParticipantsLocked(null);
}
- // Set up our transport options and initialize the default transport
- // TODO: Don't create transports that we don't need to?
- SystemConfig systemConfig = SystemConfig.getInstance();
- Set<ComponentName> transportWhitelist = systemConfig.getBackupTransportWhitelist();
-
- String transport = Settings.Secure.getString(context.getContentResolver(),
- Settings.Secure.BACKUP_TRANSPORT);
- if (TextUtils.isEmpty(transport)) {
- transport = null;
- }
- String currentTransport = transport;
- if (DEBUG) Slog.v(TAG, "Starting with transport " + currentTransport);
-
- mTransportManager = new TransportManager(context, transportWhitelist, currentTransport,
- mTransportBoundListener, backupThread.getLooper());
+ mTransportManager = transportManager;
+ mTransportManager.setTransportBoundListener(mTransportBoundListener);
mTransportManager.registerAllTransports();
// Now that we know about valid backup participants, parse any
// leftover journal files into the pending backup set
- mBackupHandler.post(() -> parseLeftoverJournals());
+ mBackupHandler.post(this::parseLeftoverJournals);
// Power management
mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
@@ -1438,14 +1470,6 @@
}
}
- // What name is this transport registered under...?
- private String getTransportName(IBackupTransport transport) {
- if (MORE_DEBUG) {
- Slog.v(TAG, "Searching for transport name of " + transport);
- }
- return mTransportManager.getTransportName(transport);
- }
-
// fire off a backup agent, blocking until it attaches or times out
@Override
public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) {
@@ -2365,19 +2389,24 @@
if (MORE_DEBUG) Slog.v(TAG, "Found the app - running clear process");
mBackupHandler.removeMessages(MSG_RETRY_CLEAR);
synchronized (mQueueLock) {
- final IBackupTransport transport =
- mTransportManager.getTransportBinder(transportName);
- if (transport == null) {
- // transport is currently unavailable -- make sure to retry
+ TransportClient transportClient =
+ mTransportManager
+ .getTransportClient(transportName, "BMS.clearBackupData()");
+ if (transportClient == null) {
+ // transport is currently unregistered -- make sure to retry
Message msg = mBackupHandler.obtainMessage(MSG_RETRY_CLEAR,
new ClearRetryParams(transportName, packageName));
mBackupHandler.sendMessageDelayed(msg, TRANSPORT_RETRY_INTERVAL);
return;
}
long oldId = Binder.clearCallingIdentity();
+ OnTaskFinishedListener listener =
+ caller ->
+ mTransportManager.disposeOfTransportClient(transportClient, caller);
mWakelock.acquire();
- Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
- new ClearParams(transport, info));
+ Message msg = mBackupHandler.obtainMessage(
+ MSG_RUN_CLEAR,
+ new ClearParams(transportClient, info, listener));
mBackupHandler.sendMessage(msg);
Binder.restoreCallingIdentity(oldId);
}
@@ -2885,6 +2914,93 @@
return whitelistedTransports;
}
+ /**
+ * 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
+ * ignored. Only the host process of the transport can change its description, otherwise a
+ * {@link SecurityException} will be thrown.
+ *
+ * @param transportComponent The identity of the transport being described.
+ * @param name A {@link String} with the new name for the transport. This is NOT for
+ * identification. MUST NOT be {@code null}.
+ * @param configurationIntent An {@link Intent} that can be passed to
+ * {@link Context#startActivity} in order to launch the transport's configuration UI. It may
+ * be {@code null} if the transport does not offer any user-facing configuration UI.
+ * @param currentDestinationString A {@link String} describing the destination to which the
+ * transport is currently sending data. MUST NOT be {@code null}.
+ * @param dataManagementIntent An {@link Intent} that can be passed to
+ * {@link Context#startActivity} in order to launch the transport's data-management UI. It
+ * may be {@code null} if the transport does not offer any user-facing data
+ * management UI.
+ * @param dataManagementLabel A {@link String} to be used as the label for the transport's data
+ * management affordance. This MUST be {@code null} when dataManagementIntent is
+ * {@code null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
+ * @throws SecurityException If the UID of the calling process differs from the package UID of
+ * {@code transportComponent} or if the caller does NOT have BACKUP permission.
+ */
+ @Override
+ public void updateTransportAttributes(
+ ComponentName transportComponent,
+ String name,
+ @Nullable Intent configurationIntent,
+ String currentDestinationString,
+ @Nullable Intent dataManagementIntent,
+ @Nullable String dataManagementLabel) {
+ updateTransportAttributes(
+ Binder.getCallingUid(),
+ transportComponent,
+ name,
+ configurationIntent,
+ currentDestinationString,
+ dataManagementIntent,
+ dataManagementLabel);
+ }
+
+ @VisibleForTesting
+ void updateTransportAttributes(
+ int callingUid,
+ ComponentName transportComponent,
+ String name,
+ @Nullable Intent configurationIntent,
+ String currentDestinationString,
+ @Nullable Intent dataManagementIntent,
+ @Nullable String dataManagementLabel) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BACKUP, "updateTransportAttributes");
+
+ Preconditions.checkNotNull(transportComponent, "transportComponent can't be null");
+ Preconditions.checkNotNull(name, "name can't be null");
+ Preconditions.checkNotNull(
+ currentDestinationString, "currentDestinationString can't be null");
+ Preconditions.checkArgument(
+ (dataManagementIntent == null) == (dataManagementLabel == null),
+ "dataManagementLabel should be null iff dataManagementIntent is null");
+
+ try {
+ int transportUid =
+ mContext.getPackageManager()
+ .getPackageUid(transportComponent.getPackageName(), 0);
+ if (callingUid != transportUid) {
+ throw new SecurityException("Only the transport can change its description");
+ }
+ } catch (NameNotFoundException e) {
+ throw new SecurityException("Transport package not found", e);
+ }
+
+ final long oldId = Binder.clearCallingIdentity();
+ try {
+ mTransportManager.describeTransport(
+ transportComponent,
+ name,
+ configurationIntent,
+ currentDestinationString,
+ dataManagementIntent,
+ dataManagementLabel);
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
+ }
+ }
+
// Select which transport to use for the next backup operation.
@Override
public String selectBackupTransport(String transport) {
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 9847edf..94a26275 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -16,6 +16,7 @@
package com.android.server.backup;
+import android.annotation.Nullable;
import android.app.backup.BackupManager;
import android.app.backup.IBackupManager;
import android.app.backup.IBackupObserver;
@@ -31,14 +32,12 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
-import android.os.Looper;
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.provider.Settings;
import android.util.Slog;
import com.android.internal.util.DumpUtils;
@@ -88,25 +87,10 @@
mSuppressFile.getParentFile().mkdirs();
}
- protected BackupManagerServiceInterface createService() {
- if (isRefactoredServiceEnabled()) {
- Slog.i(TAG, "Instantiating RefactoredBackupManagerService");
- return createRefactoredBackupManagerService();
- }
-
- Slog.i(TAG, "Instantiating BackupManagerService");
- return createBackupManagerService();
- }
-
protected boolean isBackupDisabled() {
return SystemProperties.getBoolean(BACKUP_DISABLE_PROPERTY, false);
}
- protected boolean isRefactoredServiceEnabled() {
- return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.BACKUP_REFACTORED_SERVICE_DISABLED, 0) == 0;
- }
-
protected int binderGetCallingUid() {
return Binder.getCallingUid();
}
@@ -117,11 +101,7 @@
}
protected BackupManagerServiceInterface createRefactoredBackupManagerService() {
- return new RefactoredBackupManagerService(mContext, this, mHandlerThread);
- }
-
- protected BackupManagerServiceInterface createBackupManagerService() {
- return new BackupManagerService(mContext, this, mHandlerThread);
+ return RefactoredBackupManagerService.create(mContext, this, mHandlerThread);
}
// internal control API
@@ -137,7 +117,7 @@
synchronized (this) {
if (!mSuppressFile.exists()) {
- mService = createService();
+ mService = createRefactoredBackupManagerService();
} else {
Slog.i(TAG, "Backup inactive in user " + whichUser);
}
@@ -182,7 +162,7 @@
Slog.i(TAG, "Making backup "
+ (makeActive ? "" : "in") + "active in user " + userHandle);
if (makeActive) {
- mService = createService();
+ mService = createRefactoredBackupManagerService();
mSuppressFile.delete();
} else {
mService = null;
@@ -378,6 +358,26 @@
}
@Override
+ public void updateTransportAttributes(
+ ComponentName transportComponent,
+ String name,
+ @Nullable Intent configurationIntent,
+ String currentDestinationString,
+ @Nullable Intent dataManagementIntent,
+ String dataManagementLabel) {
+ BackupManagerServiceInterface svc = mService;
+ if (svc != null) {
+ svc.updateTransportAttributes(
+ transportComponent,
+ name,
+ configurationIntent,
+ currentDestinationString,
+ dataManagementIntent,
+ dataManagementLabel);
+ }
+ }
+
+ @Override
public String selectBackupTransport(String transport) throws RemoteException {
BackupManagerServiceInterface svc = mService;
return (svc != null) ? svc.selectBackupTransport(transport) : null;
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index a2b5cb8..f8f1448 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -16,9 +16,10 @@
package com.android.server.backup;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
import android.annotation.Nullable;
import android.app.backup.BackupManager;
-import android.app.backup.BackupTransport;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -54,6 +55,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Predicate;
/**
* Handles in-memory bookkeeping of all BackupTransport objects.
@@ -80,11 +82,8 @@
* This listener is called after we bind to any transport. If it returns true, this is a valid
* transport.
*/
- private final TransportBoundListener mTransportBoundListener;
+ private TransportBoundListener mTransportBoundListener;
- private String mCurrentTransportName;
-
- /** Lock on this before accessing mValidTransports and mBoundTransports. */
private final Object mTransportLock = new Object();
/**
@@ -98,9 +97,18 @@
@GuardedBy("mTransportLock")
private final Map<String, ComponentName> mBoundTransports = new ArrayMap<>();
- /** Names of transports we've bound to at least once */
+ /** @see #getEligibleTransportComponents() */
@GuardedBy("mTransportLock")
- private final Map<String, ComponentName> mTransportsByName = new ArrayMap<>();
+ private final Set<ComponentName> mEligibleTransports = new ArraySet<>();
+
+ /** @see #getRegisteredTransportNames() */
+ @GuardedBy("mTransportLock")
+ private final Map<ComponentName, TransportDescription> mRegisteredTransportsDescriptionMap =
+ new ArrayMap<>();
+
+ @GuardedBy("mTransportLock")
+ private volatile String mCurrentTransportName;
+
/**
* Callback interface for {@link #ensureTransportReady(ComponentName, TransportReadyCallback)}.
@@ -118,8 +126,21 @@
void onFailure(int reason);
}
- TransportManager(Context context, Set<ComponentName> whitelist, String defaultTransport,
- TransportBoundListener listener, Looper looper) {
+ TransportManager(
+ Context context,
+ Set<ComponentName> whitelist,
+ String defaultTransport,
+ TransportBoundListener listener,
+ Looper looper) {
+ this(context, whitelist, defaultTransport, looper);
+ mTransportBoundListener = listener;
+ }
+
+ TransportManager(
+ Context context,
+ Set<ComponentName> whitelist,
+ String defaultTransport,
+ Looper looper) {
mContext = context;
mPackageManager = context.getPackageManager();
if (whitelist != null) {
@@ -128,11 +149,14 @@
mTransportWhitelist = new ArraySet<>();
}
mCurrentTransportName = defaultTransport;
- mTransportBoundListener = listener;
mHandler = new RebindOnTimeoutHandler(looper);
mTransportClientManager = new TransportClientManager(context);
}
+ public void setTransportBoundListener(TransportBoundListener transportBoundListener) {
+ mTransportBoundListener = transportBoundListener;
+ }
+
void onPackageAdded(String packageName) {
// New package added. Bind to all transports it contains.
synchronized (mTransportLock) {
@@ -161,6 +185,8 @@
}
}
}
+ removeTransportsIfLocked(
+ componentName -> packageName.equals(componentName.getPackageName()));
}
}
@@ -168,8 +194,10 @@
synchronized (mTransportLock) {
// Remove all changed components from mValidTransports. We'll bind to them again
// and re-add them if still valid.
+ Set<ComponentName> transportsToBeRemoved = new ArraySet<>();
for (String component : components) {
ComponentName componentName = new ComponentName(packageName, component);
+ transportsToBeRemoved.add(componentName);
TransportConnection removed = mValidTransports.remove(componentName);
if (removed != null) {
mContext.unbindService(removed);
@@ -177,10 +205,17 @@
componentName.flattenToShortString());
}
}
+ removeTransportsIfLocked(transportsToBeRemoved::contains);
bindToAllInternal(packageName, components);
}
}
+ @GuardedBy("mTransportLock")
+ private void removeTransportsIfLocked(Predicate<ComponentName> filter) {
+ mEligibleTransports.removeIf(filter);
+ mRegisteredTransportsDescriptionMap.keySet().removeIf(filter);
+ }
+
public IBackupTransport getTransportBinder(String transportName) {
synchronized (mTransportLock) {
ComponentName component = mBoundTransports.get(transportName);
@@ -213,39 +248,64 @@
}
/**
- * Returns the transport name associated with {@param transportClient} or {@code null} if not
+ * Returns the transport name associated with {@param transportComponent} or {@code null} if not
* found.
*/
@Nullable
- public String getTransportName(TransportClient transportClient) {
- ComponentName transportComponent = transportClient.getTransportComponent();
+ public String getTransportName(ComponentName transportComponent) {
synchronized (mTransportLock) {
- for (Map.Entry<String, ComponentName> transportEntry : mTransportsByName.entrySet()) {
- if (transportEntry.getValue().equals(transportComponent)) {
- return transportEntry.getKey();
- }
+ TransportDescription description =
+ mRegisteredTransportsDescriptionMap.get(transportComponent);
+ if (description == null) {
+ Slog.e(TAG, "Trying to find name of unregistered transport " + transportComponent);
+ return null;
}
- return null;
+ return description.name;
}
}
- /**
- * Returns a {@link TransportClient} for {@param transportName} or {@code null} if not found.
- *
- * @param transportName The name of the transport as returned by {@link BackupTransport#name()}.
- * @param caller A {@link String} identifying the caller for logging/debugging purposes. Check
- * {@link TransportClient#connectAsync(TransportConnectionListener, String)} for more
- * details.
- * @return A {@link TransportClient} or null if not found.
- */
+ @GuardedBy("mTransportLock")
+ @Nullable
+ private ComponentName getRegisteredTransportComponentLocked(String transportName) {
+ Map.Entry<ComponentName, TransportDescription> entry =
+ getRegisteredTransportEntryLocked(transportName);
+ return (entry == null) ? null : entry.getKey();
+ }
+
+ @GuardedBy("mTransportLock")
+ @Nullable
+ private TransportDescription getRegisteredTransportDescriptionLocked(String transportName) {
+ Map.Entry<ComponentName, TransportDescription> entry =
+ getRegisteredTransportEntryLocked(transportName);
+ return (entry == null) ? null : entry.getValue();
+ }
+
+ @GuardedBy("mTransportLock")
+ @Nullable
+ private Map.Entry<ComponentName, TransportDescription> getRegisteredTransportEntryLocked(
+ String transportName) {
+ for (Map.Entry<ComponentName, TransportDescription> entry
+ : mRegisteredTransportsDescriptionMap.entrySet()) {
+ TransportDescription description = entry.getValue();
+ if (transportName.equals(description.name)) {
+ return entry;
+ }
+ }
+ return null;
+ }
+
@Nullable
public TransportClient getTransportClient(String transportName, String caller) {
- ComponentName transportComponent = mTransportsByName.get(transportName);
- if (transportComponent == null) {
- Slog.w(TAG, "Transport " + transportName + " not registered");
- return null;
+ synchronized (mTransportLock) {
+ ComponentName component = getRegisteredTransportComponentLocked(transportName);
+ if (component == null) {
+ Slog.w(TAG, "Transport " + transportName + " not registered");
+ return null;
+ }
+ TransportDescription description = mRegisteredTransportsDescriptionMap.get(component);
+ return mTransportClientManager.getTransportClient(
+ component, description.transportDirName, caller);
}
- return mTransportClientManager.getTransportClient(transportComponent, caller);
}
/**
@@ -285,14 +345,67 @@
}
}
- String getCurrentTransportName() {
- return mCurrentTransportName;
+ /**
+ * An *eligible* transport is a service component that satisfies intent with action
+ * android.backup.TRANSPORT_HOST and returns true for
+ * {@link #isTransportTrusted(ComponentName)}. It may be registered or not registered.
+ * This method returns the {@link ComponentName}s of those transports.
+ */
+ ComponentName[] getEligibleTransportComponents() {
+ synchronized (mTransportLock) {
+ return mEligibleTransports.toArray(new ComponentName[mEligibleTransports.size()]);
+ }
}
Set<ComponentName> getTransportWhitelist() {
return mTransportWhitelist;
}
+ /**
+ * A *registered* transport is an eligible transport that has been successfully connected and
+ * that returned true for method
+ * {@link TransportBoundListener#onTransportBound(IBackupTransport)} of TransportBoundListener
+ * provided in the constructor. This method returns the names of the registered transports.
+ */
+ String[] getRegisteredTransportNames() {
+ synchronized (mTransportLock) {
+ return mRegisteredTransportsDescriptionMap.values().stream()
+ .map(transportDescription -> transportDescription.name)
+ .toArray(String[]::new);
+ }
+ }
+
+ /**
+ * Updates given values for the transport already registered and identified with
+ * {@param transportComponent}. If the transport is not registered it will log and return.
+ */
+ public void describeTransport(
+ ComponentName transportComponent,
+ String name,
+ @Nullable Intent configurationIntent,
+ String currentDestinationString,
+ @Nullable Intent dataManagementIntent,
+ String dataManagementLabel) {
+ synchronized (mTransportLock) {
+ TransportDescription description =
+ mRegisteredTransportsDescriptionMap.get(transportComponent);
+ if (description == null) {
+ Slog.e(TAG, "Transport " + name + " not registered tried to change description");
+ return;
+ }
+ description.name = name;
+ description.configurationIntent = configurationIntent;
+ description.currentDestinationString = currentDestinationString;
+ description.dataManagementIntent = dataManagementIntent;
+ description.dataManagementLabel = dataManagementLabel;
+ }
+ }
+
+ @Nullable
+ String getCurrentTransportName() {
+ return mCurrentTransportName;
+ }
+
String selectTransport(String transport) {
synchronized (mTransportLock) {
String prevTransport = mCurrentTransportName;
@@ -315,7 +428,12 @@
}
}
- void registerAllTransports() {
+
+ // This is for mocking, Mockito can't mock if package-protected and in the same package but
+ // different class loaders. Checked with the debugger and class loaders are different
+ // See https://github.com/mockito/mockito/issues/796
+ @VisibleForTesting(visibility = PACKAGE)
+ public void registerAllTransports() {
bindToAllInternal(null /* all packages */, null /* all components */);
}
@@ -391,6 +509,9 @@
Slog.d(TAG, "Binding to transport: " + transportComponentName.flattenToShortString());
// TODO: b/22388012 (Multi user backup and restore)
TransportConnection connection = new TransportConnection(transportComponentName);
+ synchronized (mTransportLock) {
+ mEligibleTransports.add(transportComponentName);
+ }
if (bindToTransport(transportComponentName, connection)) {
synchronized (mTransportLock) {
mValidTransports.put(transportComponentName, connection);
@@ -407,9 +528,25 @@
createSystemUserHandle());
}
+ /** If {@link RemoteException} is thrown the transport is guaranteed to not be registered. */
+ private void registerTransport(ComponentName transportComponent, IBackupTransport transport)
+ throws RemoteException {
+ synchronized (mTransportLock) {
+ String name = transport.name();
+ TransportDescription description = new TransportDescription(
+ name,
+ transport.transportDirName(),
+ transport.configurationIntent(),
+ transport.currentDestinationString(),
+ transport.dataManagementIntent(),
+ transport.dataManagementLabel());
+ mRegisteredTransportsDescriptionMap.put(transportComponent, description);
+ }
+ }
+
private class TransportConnection implements ServiceConnection {
- // Hold mTransportsLock to access these fields so as to provide a consistent view of them.
+ // Hold mTransportLock to access these fields so as to provide a consistent view of them.
private volatile IBackupTransport mBinder;
private final List<TransportReadyCallback> mListeners = new ArrayList<>();
private volatile String mTransportName;
@@ -433,7 +570,22 @@
mTransportName = mBinder.name();
// BackupManager requests some fields from the transport. If they are
// invalid, throw away this transport.
- success = mTransportBoundListener.onTransportBound(mBinder);
+ final boolean valid;
+ if (mTransportBoundListener != null) {
+ valid = mTransportBoundListener.onTransportBound(mBinder);
+ } else {
+ Slog.w(TAG, "setTransportBoundListener() not called, assuming transport "
+ + component + " valid");
+ valid = true;
+ }
+ if (valid) {
+ // We're now using the always-bound connection to do the registration but
+ // when we remove the always-bound code this will be in the first binding
+ // TODO: Move registration to first binding
+ registerTransport(component, mBinder);
+ // If registerTransport() hasn't thrown...
+ success = true;
+ }
} catch (RemoteException e) {
success = false;
Slog.e(TAG, "Couldn't get transport name.", e);
@@ -443,7 +595,6 @@
String componentShortString = component.flattenToShortString().intern();
if (success) {
Slog.d(TAG, "Bound to transport: " + componentShortString);
- mTransportsByName.put(mTransportName, component);
mBoundTransports.put(mTransportName, component);
for (TransportReadyCallback listener : mListeners) {
listener.onSuccess(mTransportName);
@@ -457,6 +608,7 @@
componentShortString, 0);
mContext.unbindService(this);
mValidTransports.remove(component);
+ mEligibleTransports.remove(component);
mBinder = null;
for (TransportReadyCallback listener : mListeners) {
listener.onFailure(BackupManager.ERROR_TRANSPORT_INVALID);
@@ -601,4 +753,28 @@
public static UserHandle createSystemUserHandle() {
return new UserHandle(UserHandle.USER_SYSTEM);
}
+
+ private static class TransportDescription {
+ private String name;
+ private final String transportDirName;
+ @Nullable private Intent configurationIntent;
+ private String currentDestinationString;
+ @Nullable private Intent dataManagementIntent;
+ private String dataManagementLabel;
+
+ private TransportDescription(
+ String name,
+ String transportDirName,
+ @Nullable Intent configurationIntent,
+ String currentDestinationString,
+ @Nullable Intent dataManagementIntent,
+ String dataManagementLabel) {
+ this.name = name;
+ this.transportDirName = transportDirName;
+ this.configurationIntent = configurationIntent;
+ this.currentDestinationString = currentDestinationString;
+ this.dataManagementIntent = dataManagementIntent;
+ this.dataManagementLabel = dataManagementLabel;
+ }
+ }
}
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index 9011b95..477724d 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -268,8 +268,13 @@
case MSG_RUN_CLEAR: {
ClearParams params = (ClearParams) msg.obj;
- (new PerformClearTask(backupManagerService, params.transport,
- params.packageInfo)).run();
+ Runnable task =
+ new PerformClearTask(
+ backupManagerService,
+ params.transportClient,
+ params.packageInfo,
+ params.listener);
+ task.run();
break;
}
diff --git a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
index 5be1b39..e65eb28 100644
--- a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
+++ b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
@@ -560,8 +560,8 @@
}
backupManagerService.addBackupTrace("init required; rerunning");
try {
- final String name = backupManagerService.getTransportManager().getTransportName(
- mTransportClient);
+ final String name = backupManagerService.getTransportManager()
+ .getTransportName(mTransportClient.getTransportComponent());
if (name != null) {
backupManagerService.getPendingInits().add(name);
} else {
diff --git a/services/backup/java/com/android/server/backup/internal/PerformClearTask.java b/services/backup/java/com/android/server/backup/internal/PerformClearTask.java
index 7af01ea..84ca59b 100644
--- a/services/backup/java/com/android/server/backup/internal/PerformClearTask.java
+++ b/services/backup/java/com/android/server/backup/internal/PerformClearTask.java
@@ -23,46 +23,54 @@
import com.android.internal.backup.IBackupTransport;
import com.android.server.backup.RefactoredBackupManagerService;
+import com.android.server.backup.transport.TransportClient;
import java.io.File;
public class PerformClearTask implements Runnable {
-
- private RefactoredBackupManagerService backupManagerService;
- IBackupTransport mTransport;
- PackageInfo mPackage;
+ private final RefactoredBackupManagerService mBackupManagerService;
+ private final TransportClient mTransportClient;
+ private final PackageInfo mPackage;
+ private final OnTaskFinishedListener mListener;
PerformClearTask(RefactoredBackupManagerService backupManagerService,
- IBackupTransport transport, PackageInfo packageInfo) {
- this.backupManagerService = backupManagerService;
- mTransport = transport;
+ TransportClient transportClient, PackageInfo packageInfo,
+ OnTaskFinishedListener listener) {
+ mBackupManagerService = backupManagerService;
+ mTransportClient = transportClient;
mPackage = packageInfo;
+ mListener = listener;
}
public void run() {
+ String callerLogString = "PerformClearTask.run()";
+ IBackupTransport transport = null;
try {
// Clear the on-device backup state to ensure a full backup next time
- File stateDir = new File(backupManagerService.getBaseStateDir(),
- mTransport.transportDirName());
+ File stateDir = new File(mBackupManagerService.getBaseStateDir(),
+ mTransportClient.getTransportDirName());
File stateFile = new File(stateDir, mPackage.packageName);
stateFile.delete();
+ transport = mTransportClient.connectOrThrow(callerLogString);
// Tell the transport to remove all the persistent storage for the app
// TODO - need to handle failures
- mTransport.clearBackupData(mPackage);
+ transport.clearBackupData(mPackage);
} catch (Exception e) {
Slog.e(TAG, "Transport threw clearing data for " + mPackage + ": " + e.getMessage());
} finally {
- try {
- // TODO - need to handle failures
- mTransport.finishBackup();
- } catch (Exception e) {
- // Nothing we can do here, alas
- Slog.e(TAG, "Unable to mark clear operation finished: " + e.getMessage());
+ if (transport != null) {
+ try {
+ // TODO - need to handle failures
+ transport.finishBackup();
+ } catch (Exception e) {
+ // Nothing we can do here, alas
+ Slog.e(TAG, "Unable to mark clear operation finished: " + e.getMessage());
+ }
}
-
+ mListener.onFinished(callerLogString);
// Last but not least, release the cpu
- backupManagerService.getWakelock().release();
+ mBackupManagerService.getWakelock().release();
}
}
}
diff --git a/services/backup/java/com/android/server/backup/params/ClearParams.java b/services/backup/java/com/android/server/backup/params/ClearParams.java
index d744efc..dc3bba0 100644
--- a/services/backup/java/com/android/server/backup/params/ClearParams.java
+++ b/services/backup/java/com/android/server/backup/params/ClearParams.java
@@ -18,15 +18,20 @@
import android.content.pm.PackageInfo;
-import com.android.internal.backup.IBackupTransport;
+import com.android.server.backup.internal.OnTaskFinishedListener;
+import com.android.server.backup.transport.TransportClient;
public class ClearParams {
-
- public IBackupTransport transport;
+ public TransportClient transportClient;
public PackageInfo packageInfo;
+ public OnTaskFinishedListener listener;
- public ClearParams(IBackupTransport _transport, PackageInfo _info) {
- transport = _transport;
- packageInfo = _info;
+ public ClearParams(
+ TransportClient transportClient,
+ PackageInfo packageInfo,
+ OnTaskFinishedListener listener) {
+ this.transportClient = transportClient;
+ this.packageInfo = packageInfo;
+ this.listener = listener;
}
}
diff --git a/services/backup/java/com/android/server/backup/params/ClearRetryParams.java b/services/backup/java/com/android/server/backup/params/ClearRetryParams.java
index fcf66e4..41b5641 100644
--- a/services/backup/java/com/android/server/backup/params/ClearRetryParams.java
+++ b/services/backup/java/com/android/server/backup/params/ClearRetryParams.java
@@ -17,12 +17,11 @@
package com.android.server.backup.params;
public class ClearRetryParams {
-
public String transportName;
public String packageName;
- public ClearRetryParams(String transport, String pkg) {
- transportName = transport;
- packageName = pkg;
+ public ClearRetryParams(String transportName, String packageName) {
+ this.transportName = transportName;
+ this.packageName = packageName;
}
}
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index b538c6d..5884dc5 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -495,14 +495,14 @@
return;
}
- if (metaInfo.versionCode > mCurrentPackage.versionCode) {
+ if (metaInfo.versionCode > mCurrentPackage.getLongVersionCode()) {
// Data is from a "newer" version of the app than we have currently
// installed. If the app has not declared that it is prepared to
// handle this case, we do not attempt the restore.
if ((mCurrentPackage.applicationInfo.flags
& ApplicationInfo.FLAG_RESTORE_ANY_VERSION) == 0) {
String message = "Source version " + metaInfo.versionCode
- + " > installed version " + mCurrentPackage.versionCode;
+ + " > installed version " + mCurrentPackage.getLongVersionCode();
Slog.w(TAG, "Package " + pkgName + ": " + message);
Bundle monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(null,
BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION,
@@ -522,7 +522,7 @@
} else {
if (DEBUG) {
Slog.v(TAG, "Source version " + metaInfo.versionCode
- + " > installed version " + mCurrentPackage.versionCode
+ + " > installed version " + mCurrentPackage.getLongVersionCode()
+ " but restoreAnyVersion");
}
Bundle monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(null,
@@ -543,7 +543,7 @@
Slog.v(TAG, "Package " + pkgName
+ " restore version [" + metaInfo.versionCode
+ "] is compatible with installed version ["
- + mCurrentPackage.versionCode + "]");
+ + mCurrentPackage.getLongVersionCode() + "]");
}
// Reset per-package preconditions and fire the appropriate next state
@@ -635,7 +635,7 @@
}
// Guts of a key/value restore operation
- void initiateOneRestore(PackageInfo app, int appVersionCode) {
+ void initiateOneRestore(PackageInfo app, long appVersionCode) {
final String packageName = app.packageName;
if (DEBUG) {
diff --git a/services/backup/java/com/android/server/backup/transport/TransportClient.java b/services/backup/java/com/android/server/backup/transport/TransportClient.java
index 65f9502..2c7a0eb 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportClient.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportClient.java
@@ -68,6 +68,7 @@
private final Intent mBindIntent;
private final String mIdentifier;
private final ComponentName mTransportComponent;
+ private final String mTransportDirName;
private final Handler mListenerHandler;
private final String mPrefixForLog;
private final Object mStateLock = new Object();
@@ -86,8 +87,15 @@
Context context,
Intent bindIntent,
ComponentName transportComponent,
+ String transportDirName,
String identifier) {
- this(context, bindIntent, transportComponent, identifier, Handler.getMain());
+ this(
+ context,
+ bindIntent,
+ transportComponent,
+ transportDirName,
+ identifier,
+ new Handler(Looper.getMainLooper()));
}
@VisibleForTesting
@@ -95,10 +103,12 @@
Context context,
Intent bindIntent,
ComponentName transportComponent,
+ String transportDirName,
String identifier,
Handler listenerHandler) {
mContext = context;
mTransportComponent = transportComponent;
+ mTransportDirName = transportDirName;
mBindIntent = bindIntent;
mIdentifier = identifier;
mListenerHandler = listenerHandler;
@@ -112,6 +122,10 @@
return mTransportComponent;
}
+ public String getTransportDirName() {
+ return mTransportDirName;
+ }
+
// Calls to onServiceDisconnected() or onBindingDied() turn TransportClient UNUSABLE. After one
// of these calls, if a binding happen again the new service can be a different instance. Since
// transports are stateful, we don't want a new instance responding for an old instance's state.
diff --git a/services/backup/java/com/android/server/backup/transport/TransportClientManager.java b/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
index 1cbe7471..bb550f6 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
@@ -23,6 +23,7 @@
import android.content.Intent;
import android.util.Log;
+import com.android.internal.backup.IBackupTransport;
import com.android.server.backup.TransportManager;
/**
@@ -47,12 +48,17 @@
* transportComponent}.
*
* @param transportComponent The {@link ComponentName} of the transport.
+ * @param transportDirName The {@link String} returned by
+ * {@link IBackupTransport#transportDirName()} at registration.
* @param caller A {@link String} identifying the caller for logging/debugging purposes. Check
* {@link TransportClient#connectAsync(TransportConnectionListener, String)} for more
* details.
* @return A {@link TransportClient}.
*/
- public TransportClient getTransportClient(ComponentName transportComponent, String caller) {
+ public TransportClient getTransportClient(
+ ComponentName transportComponent,
+ String transportDirName,
+ String caller) {
Intent bindIntent =
new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(transportComponent);
synchronized (mTransportClientsLock) {
@@ -61,6 +67,7 @@
mContext,
bindIntent,
transportComponent,
+ transportDirName,
Integer.toString(mTransportClientsCreated));
mTransportClientsCreated++;
TransportUtils.log(Log.DEBUG, TAG, caller, "Retrieving " + transportClient);
diff --git a/services/backup/java/com/android/server/backup/transport/TransportNotAvailableException.java b/services/backup/java/com/android/server/backup/transport/TransportNotAvailableException.java
index c4e5a1d..c08eb7f 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportNotAvailableException.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportNotAvailableException.java
@@ -16,6 +16,8 @@
package com.android.server.backup.transport;
+import android.util.AndroidException;
+
import com.android.internal.backup.IBackupTransport;
/**
@@ -25,7 +27,7 @@
*
* @see TransportClient#connectAsync(TransportConnectionListener, String)
*/
-public class TransportNotAvailableException extends Exception {
+public class TransportNotAvailableException extends AndroidException {
TransportNotAvailableException() {
super("Transport not available");
}
diff --git a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java
index 734fa1d..010684e 100644
--- a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java
@@ -56,6 +56,8 @@
pkg.packageName);
bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION,
pkg.versionCode);
+ bundle.putLong(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION,
+ pkg.getLongVersionCode());
}
if (extras != null) {
bundle.putAll(extras);
diff --git a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java
index b3e20dc..a731fc9 100644
--- a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java
@@ -97,7 +97,7 @@
printer.println(Integer.toString(BACKUP_MANIFEST_VERSION));
printer.println(pkg.packageName);
- printer.println(Integer.toString(pkg.versionCode));
+ printer.println(Long.toString(pkg.getLongVersionCode()));
printer.println(Integer.toString(Build.VERSION.SDK_INT));
String installerName = packageManager.getInstallerPackageName(pkg.packageName);
diff --git a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
index 2910ba2..ff9cb56 100644
--- a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
+++ b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
@@ -422,7 +422,7 @@
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
null);
policy = RestorePolicy.ACCEPT;
- } else if (pkgInfo.versionCode >= info.version) {
+ } else if (pkgInfo.getLongVersionCode() >= info.version) {
Slog.i(TAG, "Sig + version match; taking data");
policy = RestorePolicy.ACCEPT;
mMonitor = BackupManagerMonitorUtils.monitorEvent(
@@ -439,7 +439,7 @@
Slog.i(TAG, "Data version " + info.version
+ " is newer than installed "
+ "version "
- + pkgInfo.versionCode
+ + pkgInfo.getLongVersionCode()
+ " - requiring apk");
policy = RestorePolicy.ACCEPT_IF_APK;
} else {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index f2f01cf..d44fe4d 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -21,6 +21,7 @@
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.Preconditions.checkState;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
import android.Manifest;
import android.annotation.CheckResult;
@@ -69,6 +70,7 @@
import com.android.internal.notification.NotificationAccessConfirmationActivityContract;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.FgThread;
import com.android.server.SystemService;
@@ -440,32 +442,35 @@
return;
}
- Binder.withCleanCallingIdentity(() -> {
- try {
- if (containsEither(packageInfo.requestedPermissions,
- Manifest.permission.RUN_IN_BACKGROUND,
- Manifest.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND)) {
- mIdleController.addPowerSaveWhitelistApp(packageInfo.packageName);
- } else {
- mIdleController.removePowerSaveWhitelistApp(packageInfo.packageName);
- }
- } catch (RemoteException e) {
- /* ignore - local call */
- }
+ Binder.withCleanCallingIdentity(obtainRunnable(CompanionDeviceManagerService::
+ updateSpecialAccessPermissionAsSystem, this, packageInfo).recycleOnUse());
+ }
- NetworkPolicyManager networkPolicyManager = NetworkPolicyManager.from(getContext());
+ private void updateSpecialAccessPermissionAsSystem(PackageInfo packageInfo) {
+ try {
if (containsEither(packageInfo.requestedPermissions,
- Manifest.permission.USE_DATA_IN_BACKGROUND,
- Manifest.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND)) {
- networkPolicyManager.addUidPolicy(
- packageInfo.applicationInfo.uid,
- NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND);
+ android.Manifest.permission.RUN_IN_BACKGROUND,
+ android.Manifest.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND)) {
+ mIdleController.addPowerSaveWhitelistApp(packageInfo.packageName);
} else {
- networkPolicyManager.removeUidPolicy(
- packageInfo.applicationInfo.uid,
- NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND);
+ mIdleController.removePowerSaveWhitelistApp(packageInfo.packageName);
}
- });
+ } catch (RemoteException e) {
+ /* ignore - local call */
+ }
+
+ NetworkPolicyManager networkPolicyManager = NetworkPolicyManager.from(getContext());
+ if (containsEither(packageInfo.requestedPermissions,
+ android.Manifest.permission.USE_DATA_IN_BACKGROUND,
+ android.Manifest.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND)) {
+ networkPolicyManager.addUidPolicy(
+ packageInfo.applicationInfo.uid,
+ NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND);
+ } else {
+ networkPolicyManager.removeUidPolicy(
+ packageInfo.applicationInfo.uid,
+ NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND);
+ }
}
private static <T> boolean containsEither(T[] array, T a, T b) {
@@ -474,17 +479,17 @@
@Nullable
private PackageInfo getPackageInfo(String packageName, int userId) {
- return Binder.withCleanCallingIdentity(() -> {
+ return Binder.withCleanCallingIdentity(PooledLambda.obtainSupplier((context, pkg, id) -> {
try {
- return getContext().getPackageManager().getPackageInfoAsUser(
- packageName,
+ return context.getPackageManager().getPackageInfoAsUser(
+ pkg,
PackageManager.GET_PERMISSIONS | PackageManager.GET_CONFIGURATIONS,
- userId);
+ id);
} catch (PackageManager.NameNotFoundException e) {
- Slog.e(LOG_TAG, "Failed to get PackageInfo for package " + packageName, e);
+ Slog.e(LOG_TAG, "Failed to get PackageInfo for package " + pkg, e);
return null;
}
- });
+ }, getContext(), packageName, userId).recycleOnUse());
}
private void recordAssociation(String priviledgedPackage, String deviceAddress) {
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 3904fc9..ca15249 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -46,16 +46,15 @@
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.WorkSource;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.KeyValueListParser;
import android.util.Log;
import android.util.Slog;
@@ -81,6 +80,7 @@
import java.util.Random;
import java.util.TimeZone;
import java.util.TreeSet;
+import java.util.function.Predicate;
import static android.app.AlarmManager.RTC_WAKEUP;
import static android.app.AlarmManager.RTC;
@@ -88,11 +88,17 @@
import static android.app.AlarmManager.ELAPSED_REALTIME;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.IAppOpsCallback;
-import com.android.internal.app.IAppOpsService;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.LocalLog;
+import com.android.server.ForceAppStandbyTracker.Listener;
+/**
+ * Alarm manager implementaion.
+ *
+ * Unit test:
+ atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/AlarmManagerServiceTest.java
+ */
class AlarmManagerService extends SystemService {
private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP;
private static final int RTC_MASK = 1 << RTC;
@@ -131,13 +137,10 @@
final LocalLog mLog = new LocalLog(TAG);
AppOpsManager mAppOps;
- IAppOpsService mAppOpsService;
DeviceIdleController.LocalService mLocalDeviceIdleController;
final Object mLock = new Object();
- ArraySet<String> mForcedAppStandbyPackages = new ArraySet<>();
- SparseBooleanArray mForegroundUids = new SparseBooleanArray();
// List of alarms per uid deferred due to user applied background restrictions on the source app
SparseArray<ArrayList<Alarm>> mPendingBackgroundAlarms = new SparseArray<>();
long mNativeData;
@@ -184,12 +187,6 @@
int mSystemUiUid;
/**
- * The current set of user whitelisted apps for device idle mode, meaning these are allowed
- * to freely schedule alarms.
- */
- int[] mDeviceIdleUserWhitelist = new int[0];
-
- /**
* For each uid, this is the last time we dispatched an "allow while idle" alarm,
* used to determine the earliest we can dispatch the next such alarm. Times are in the
* 'elapsed' timebase.
@@ -223,6 +220,8 @@
private final SparseArray<AlarmManager.AlarmClockInfo> mHandlerSparseAlarmClockArray =
new SparseArray<>();
+ private final ForceAppStandbyTracker mForceAppStandbyTracker;
+
/**
* All times are in milliseconds. These constants are kept synchronized with the system
* global Settings. Any access to this class or its fields should be done while
@@ -757,6 +756,9 @@
public AlarmManagerService(Context context) {
super(context);
mConstants = new Constants(mHandler);
+
+ mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context);
+ mForceAppStandbyTracker.addListener(mForceAppStandbyListener);
}
static long convertToElapsed(long when, int type) {
@@ -894,17 +896,48 @@
deliverPendingBackgroundAlarmsLocked(alarmsToDeliver, SystemClock.elapsedRealtime());
}
- void sendPendingBackgroundAlarmsForAppIdLocked(int appId) {
+ /**
+ * Check all alarms in {@link #mPendingBackgroundAlarms} and send the ones that are not
+ * restricted.
+ *
+ * This is only called when the global "force all apps-standby" flag changes or when the
+ * power save whitelist changes, so it's okay to be slow.
+ */
+ void sendAllUnrestrictedPendingBackgroundAlarmsLocked() {
final ArrayList<Alarm> alarmsToDeliver = new ArrayList<>();
- for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
- final int uid = mPendingBackgroundAlarms.keyAt(i);
- final ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.valueAt(i);
- if (UserHandle.getAppId(uid) == appId) {
- alarmsToDeliver.addAll(alarmsForUid);
- mPendingBackgroundAlarms.removeAt(i);
+
+ findAllUnrestrictedPendingBackgroundAlarmsLockedInner(
+ mPendingBackgroundAlarms, alarmsToDeliver, this::isBackgroundRestricted);
+
+ if (alarmsToDeliver.size() > 0) {
+ deliverPendingBackgroundAlarmsLocked(alarmsToDeliver, SystemClock.elapsedRealtime());
+ }
+ }
+
+ @VisibleForTesting
+ static void findAllUnrestrictedPendingBackgroundAlarmsLockedInner(
+ SparseArray<ArrayList<Alarm>> pendingAlarms, ArrayList<Alarm> unrestrictedAlarms,
+ Predicate<Alarm> isBackgroundRestricted) {
+
+ for (int uidIndex = pendingAlarms.size() - 1; uidIndex >= 0; uidIndex--) {
+ final int uid = pendingAlarms.keyAt(uidIndex);
+ final ArrayList<Alarm> alarmsForUid = pendingAlarms.valueAt(uidIndex);
+
+ for (int alarmIndex = alarmsForUid.size() - 1; alarmIndex >= 0; alarmIndex--) {
+ final Alarm alarm = alarmsForUid.get(alarmIndex);
+
+ if (isBackgroundRestricted.test(alarm)) {
+ continue;
+ }
+
+ unrestrictedAlarms.add(alarm);
+ alarmsForUid.remove(alarmIndex);
+ }
+
+ if (alarmsForUid.size() == 0) {
+ pendingAlarms.removeAt(uidIndex);
}
}
- deliverPendingBackgroundAlarmsLocked(alarmsToDeliver, SystemClock.elapsedRealtime());
}
private void deliverPendingBackgroundAlarmsLocked(ArrayList<Alarm> alarms, long nowELAPSED) {
@@ -1234,10 +1267,8 @@
} catch (RemoteException e) {
// ignored; both services live in system_server
}
- mAppOpsService = IAppOpsService.Stub.asInterface(
- ServiceManager.getService(Context.APP_OPS_SERVICE));
publishBinderService(Context.ALARM_SERVICE, mService);
- publishLocalService(LocalService.class, new LocalService());
+ mForceAppStandbyTracker.start();
}
@Override
@@ -1247,13 +1278,6 @@
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
mLocalDeviceIdleController
= LocalServices.getService(DeviceIdleController.LocalService.class);
- try {
- mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, null,
- new AppOpsWatcher());
- } catch (RemoteException rexc) {
- // Shouldn't happen as they are in the same process.
- Slog.e(TAG, "AppOps service not reachable", rexc);
- }
}
}
@@ -1582,8 +1606,7 @@
// timing restrictions.
} else if (workSource == null && (callingUid < Process.FIRST_APPLICATION_UID
|| callingUid == mSystemUiUid
- || Arrays.binarySearch(mDeviceIdleUserWhitelist,
- UserHandle.getAppId(callingUid)) >= 0)) {
+ || mForceAppStandbyTracker.isUidPowerSaveWhitelisted(callingUid))) {
flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
flags &= ~AlarmManager.FLAG_ALLOW_WHILE_IDLE;
}
@@ -1660,24 +1683,14 @@
}
};
- public final class LocalService {
- public void setDeviceIdleUserWhitelist(int[] appids) {
- setDeviceIdleUserWhitelistImpl(appids);
- }
- }
-
void dumpImpl(PrintWriter pw) {
synchronized (mLock) {
pw.println("Current Alarm Manager state:");
mConstants.dump(pw);
pw.println();
- pw.print(" Foreground uids: [");
- for (int i = 0; i < mForegroundUids.size(); i++) {
- if (mForegroundUids.valueAt(i)) pw.print(mForegroundUids.keyAt(i) + " ");
- }
- pw.println("]");
- pw.println(" Forced app standby packages: " + mForcedAppStandbyPackages);
+ mForceAppStandbyTracker.dump(pw, " ");
+
final long nowRTC = System.currentTimeMillis();
final long nowELAPSED = SystemClock.elapsedRealtime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@@ -1717,7 +1730,6 @@
pw.print(" set at "); TimeUtils.formatDuration(mLastWakeupSet, nowELAPSED, pw);
pw.println();
pw.print(" Num time change events: "); pw.println(mNumTimeChanged);
- pw.println(" mDeviceIdleUserWhitelist=" + Arrays.toString(mDeviceIdleUserWhitelist));
pw.println();
pw.println(" Next alarm clock information: ");
@@ -1990,15 +2002,8 @@
mConstants.dumpProto(proto, AlarmManagerServiceProto.SETTINGS);
- final int foregroundUidsSize = mForegroundUids.size();
- for (int i = 0; i < foregroundUidsSize; i++) {
- if (mForegroundUids.valueAt(i)) {
- proto.write(AlarmManagerServiceProto.FOREGROUND_UIDS, mForegroundUids.keyAt(i));
- }
- }
- for (String pkg : mForcedAppStandbyPackages) {
- proto.write(AlarmManagerServiceProto.FORCED_APP_STANDBY_PACKAGES, pkg);
- }
+ mForceAppStandbyTracker.dumpProto(proto,
+ AlarmManagerServiceProto.FORCE_APP_STANDBY_TRACKER);
proto.write(AlarmManagerServiceProto.IS_INTERACTIVE, mInteractive);
if (!mInteractive) {
@@ -2022,9 +2027,6 @@
proto.write(AlarmManagerServiceProto.TIME_SINCE_LAST_WAKEUP_SET_MS,
nowElapsed - mLastWakeupSet);
proto.write(AlarmManagerServiceProto.TIME_CHANGE_EVENT_COUNT, mNumTimeChanged);
- for (int i : mDeviceIdleUserWhitelist) {
- proto.write(AlarmManagerServiceProto.DEVICE_IDLE_USER_WHITELIST_APP_IDS, i);
- }
final TreeSet<Integer> users = new TreeSet<>();
final int nextAlarmClockForUserSize = mNextAlarmClockForUser.size();
@@ -2266,28 +2268,6 @@
}
}
- void setDeviceIdleUserWhitelistImpl(int[] appids) {
- synchronized (mLock) {
- // appids are sorted, just send pending alarms for any new appids added to the whitelist
- int i = 0, j = 0;
- while (i < appids.length) {
- while (j < mDeviceIdleUserWhitelist.length
- && mDeviceIdleUserWhitelist[j] < appids[i]) {
- j++;
- }
- if (j < mDeviceIdleUserWhitelist.length
- && appids[i] != mDeviceIdleUserWhitelist[j]) {
- if (DEBUG_BG_LIMIT) {
- Slog.d(TAG, "Sending blocked alarms for whitelisted appid " + appids[j]);
- }
- sendPendingBackgroundAlarmsForAppIdLocked(appids[j]);
- }
- i++;
- }
- mDeviceIdleUserWhitelist = appids;
- }
- }
-
AlarmManager.AlarmClockInfo getNextAlarmClockImpl(int userId) {
synchronized (mLock) {
return mNextAlarmClockForUser.get(userId);
@@ -2710,9 +2690,7 @@
final String sourcePackage =
(alarm.operation != null) ? alarm.operation.getCreatorPackage() : alarm.packageName;
final int sourceUid = alarm.creatorUid;
- return mForcedAppStandbyPackages.contains(sourcePackage) && !mForegroundUids.get(sourceUid)
- && Arrays.binarySearch(mDeviceIdleUserWhitelist, UserHandle.getAppId(sourceUid))
- < 0;
+ return mForceAppStandbyTracker.areAlarmsRestricted(sourceUid, sourcePackage);
}
private native long init();
@@ -2859,7 +2837,8 @@
}
}
- private static class Alarm {
+ @VisibleForTesting
+ static class Alarm {
public final int type;
public final long origWhen;
public final boolean wakeup;
@@ -3073,6 +3052,11 @@
for (int i=0; i<triggerList.size(); i++) {
Alarm alarm = triggerList.get(i);
final boolean allowWhileIdle = (alarm.flags&AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0;
+ if (alarm.wakeup) {
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "Dispatch wakeup alarm to " + alarm.packageName);
+ } else {
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "Dispatch non-wakeup alarm to " + alarm.packageName);
+ }
try {
if (localLOGV) {
Slog.v(TAG, "sending alarm " + alarm);
@@ -3092,6 +3076,7 @@
} catch (RuntimeException e) {
Slog.w(TAG, "Failure sending alarm.", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
@@ -3476,17 +3461,10 @@
if (disabled) {
removeForStoppedLocked(uid);
}
- mForegroundUids.delete(uid);
}
}
@Override public void onUidActive(int uid) {
- synchronized (mLock) {
- if (!mForegroundUids.get(uid)) {
- mForegroundUids.put(uid, true);
- sendPendingBackgroundAlarmsLocked(uid, null);
- }
- }
}
@Override public void onUidIdle(int uid, boolean disabled) {
@@ -3494,7 +3472,6 @@
if (disabled) {
removeForStoppedLocked(uid);
}
- mForegroundUids.delete(uid);
}
}
@@ -3502,27 +3479,29 @@
}
};
- private final class AppOpsWatcher extends IAppOpsCallback.Stub {
+
+ private final Listener mForceAppStandbyListener = new Listener() {
@Override
- public void opChanged(int op, int uid, String packageName) throws RemoteException {
+ public void unblockAllUnrestrictedAlarms() {
synchronized (mLock) {
- final int mode = mAppOpsService.checkOperation(op, uid, packageName);
- if (DEBUG_BG_LIMIT) {
- Slog.d(TAG,
- "Appop changed for " + uid + ", " + packageName + " to " + mode);
- }
- final boolean changed;
- if (mode != AppOpsManager.MODE_ALLOWED) {
- changed = mForcedAppStandbyPackages.add(packageName);
- } else {
- changed = mForcedAppStandbyPackages.remove(packageName);
- }
- if (changed && mode == AppOpsManager.MODE_ALLOWED) {
- sendPendingBackgroundAlarmsLocked(uid, packageName);
- }
+ sendAllUnrestrictedPendingBackgroundAlarmsLocked();
}
}
- }
+
+ @Override
+ public void unblockAlarmsForUid(int uid) {
+ synchronized (mLock) {
+ sendPendingBackgroundAlarmsLocked(uid, null);
+ }
+ }
+
+ @Override
+ public void unblockAlarmsForUidPackage(int uid, String packageName) {
+ synchronized (mLock) {
+ sendPendingBackgroundAlarmsLocked(uid, packageName);
+ }
+ }
+ };
private final BroadcastStats getStatsLocked(PendingIntent pi) {
String pkg = pi.getCreatorPackage();
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index c34c30c..763a4e4 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -67,6 +67,7 @@
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.LinkedList;
+import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -79,15 +80,14 @@
private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
- private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid";
- private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
- private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
+ private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID = "bluetooth_addr_valid";
+ private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS = "bluetooth_address";
+ private static final String SECURE_SETTINGS_BLUETOOTH_NAME = "bluetooth_name";
private static final int ACTIVE_LOG_MAX_SIZE = 20;
private static final int CRASH_LOG_MAX_SIZE = 100;
private static final String REASON_AIRPLANE_MODE = "airplane mode";
private static final String REASON_DISALLOWED = "disallowed by system";
- private static final String REASON_SHARING_DISALLOWED = "sharing disallowed by system";
private static final String REASON_RESTARTED = "automatic restart";
private static final String REASON_START_CRASH = "turn-on crash";
private static final String REASON_SYSTEM_BOOT = "system boot";
@@ -130,14 +130,14 @@
private static final int MAX_ERROR_RESTART_RETRIES = 6;
// Bluetooth persisted setting is off
- private static final int BLUETOOTH_OFF=0;
+ private static final int BLUETOOTH_OFF = 0;
// Bluetooth persisted setting is on
// and Airplane mode won't affect Bluetooth state at start up
- private static final int BLUETOOTH_ON_BLUETOOTH=1;
+ private static final int BLUETOOTH_ON_BLUETOOTH = 1;
// Bluetooth persisted setting is on
// but Airplane mode will affect Bluetooth state at start up
// and Airplane mode will have higher priority.
- private static final int BLUETOOTH_ON_AIRPLANE=2;
+ private static final int BLUETOOTH_ON_AIRPLANE = 2;
private static final int SERVICE_IBLUETOOTH = 1;
private static final int SERVICE_IBLUETOOTHGATT = 2;
@@ -154,8 +154,7 @@
private IBinder mBluetoothBinder;
private IBluetooth mBluetooth;
private IBluetoothGatt mBluetoothGatt;
- private final ReentrantReadWriteLock mBluetoothLock =
- new ReentrantReadWriteLock();
+ private final ReentrantReadWriteLock mBluetoothLock = new ReentrantReadWriteLock();
private boolean mBinding;
private boolean mUnbinding;
@@ -175,7 +174,7 @@
private boolean mEnable;
private long mTimestamp;
- public ActiveLog(String packageName, boolean enable, long timestamp) {
+ ActiveLog(String packageName, boolean enable, long timestamp) {
mPackageName = packageName;
mEnable = enable;
mTimestamp = timestamp;
@@ -186,8 +185,8 @@
}
public String toString() {
- return timeToLog(mTimestamp) + (mEnable ? " Enabled " : " Disabled ") + " by "
- + mPackageName;
+ return timeToLog(mTimestamp) + (mEnable ? " Enabled " : " Disabled ") + " by "
+ + mPackageName;
}
}
@@ -203,7 +202,8 @@
private boolean mEnableExternal;
// Map of apps registered to keep BLE scanning on.
- private Map<IBinder, ClientDeathRecipient> mBleApps = new ConcurrentHashMap<IBinder, ClientDeathRecipient>();
+ private Map<IBinder, ClientDeathRecipient> mBleApps =
+ new ConcurrentHashMap<IBinder, ClientDeathRecipient>();
private int mState;
private final BluetoothHandler mHandler;
@@ -212,51 +212,52 @@
// Save a ProfileServiceConnections object for each of the bound
// bluetooth profile services
- private final Map <Integer, ProfileServiceConnections> mProfileServices =
- new HashMap <Integer, ProfileServiceConnections>();
+ private final Map<Integer, ProfileServiceConnections> mProfileServices =
+ new HashMap<Integer, ProfileServiceConnections>();
private final boolean mPermissionReviewRequired;
private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
@Override
- public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
- Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
+ public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
+ Message msg =
+ mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE, prevState, newState);
mHandler.sendMessage(msg);
}
};
private final UserRestrictionsListener mUserRestrictionsListener =
new UserRestrictionsListener() {
- @Override
- public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
- Bundle prevRestrictions) {
+ @Override
+ public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
+ Bundle prevRestrictions) {
- if (UserRestrictionsUtils.restrictionsChanged(prevRestrictions, newRestrictions,
- UserManager.DISALLOW_BLUETOOTH_SHARING)) {
- updateOppLauncherComponentState(userId, newRestrictions.getBoolean(
- UserManager.DISALLOW_BLUETOOTH_SHARING));
- }
+ if (UserRestrictionsUtils.restrictionsChanged(prevRestrictions, newRestrictions,
+ UserManager.DISALLOW_BLUETOOTH_SHARING)) {
+ updateOppLauncherComponentState(userId,
+ newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH_SHARING));
+ }
- // DISALLOW_BLUETOOTH can only be set by DO or PO on the system user.
- if (userId == UserHandle.USER_SYSTEM &&
- UserRestrictionsUtils.restrictionsChanged(
- prevRestrictions, newRestrictions, UserManager.DISALLOW_BLUETOOTH)) {
- if (userId == UserHandle.USER_SYSTEM && newRestrictions.getBoolean(
- UserManager.DISALLOW_BLUETOOTH)) {
- updateOppLauncherComponentState(userId, true); // Sharing disallowed
- sendDisableMsg(REASON_DISALLOWED);
- } else {
- updateOppLauncherComponentState(userId, newRestrictions.getBoolean(
- UserManager.DISALLOW_BLUETOOTH_SHARING));
+ // DISALLOW_BLUETOOTH can only be set by DO or PO on the system user.
+ if (userId == UserHandle.USER_SYSTEM
+ && UserRestrictionsUtils.restrictionsChanged(prevRestrictions,
+ newRestrictions, UserManager.DISALLOW_BLUETOOTH)) {
+ if (userId == UserHandle.USER_SYSTEM && newRestrictions.getBoolean(
+ UserManager.DISALLOW_BLUETOOTH)) {
+ updateOppLauncherComponentState(userId, true); // Sharing disallowed
+ sendDisableMsg(REASON_DISALLOWED);
+ } else {
+ updateOppLauncherComponentState(userId, newRestrictions.getBoolean(
+ UserManager.DISALLOW_BLUETOOTH_SHARING));
+ }
+ }
}
- }
- }
- };
+ };
private final ContentObserver mAirplaneModeObserver = new ContentObserver(null) {
@Override
public void onChange(boolean unused) {
- synchronized(this) {
+ synchronized (this) {
if (isBluetoothPersistedStateOn()) {
if (isAirplaneModeOn()) {
persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
@@ -278,8 +279,9 @@
mBluetoothLock.readLock().unlock();
}
- Slog.d(TAG, "Airplane Mode change - current state: " +
- BluetoothAdapter.nameForState(st));
+ Slog.d(TAG,
+ "Airplane Mode change - current state: " + BluetoothAdapter.nameForState(
+ st));
if (isAirplaneModeOn()) {
// Clear registered LE apps to force shut-off
@@ -295,11 +297,11 @@
mEnableExternal = false;
}
} catch (RemoteException e) {
- Slog.e(TAG,"Unable to call onBrEdrDown", e);
+ Slog.e(TAG, "Unable to call onBrEdrDown", e);
} finally {
mBluetoothLock.readLock().unlock();
}
- } else if (st == BluetoothAdapter.STATE_ON){
+ } else if (st == BluetoothAdapter.STATE_ON) {
sendDisableMsg(REASON_AIRPLANE_MODE);
}
} else if (mEnableExternal) {
@@ -315,35 +317,42 @@
String action = intent.getAction();
if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
- if (DBG) Slog.d(TAG, "Bluetooth Adapter name changed to " + newName);
+ if (DBG) {
+ Slog.d(TAG, "Bluetooth Adapter name changed to " + newName);
+ }
if (newName != null) {
storeNameAndAddress(newName, null);
}
} else if (BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED.equals(action)) {
String newAddress = intent.getStringExtra(BluetoothAdapter.EXTRA_BLUETOOTH_ADDRESS);
if (newAddress != null) {
- if (DBG) Slog.d(TAG, "Bluetooth Adapter address changed to " + newAddress);
+ if (DBG) {
+ Slog.d(TAG, "Bluetooth Adapter address changed to " + newAddress);
+ }
storeNameAndAddress(null, newAddress);
} else {
- if (DBG) Slog.e(TAG, "No Bluetooth Adapter address parameter found");
+ if (DBG) {
+ Slog.e(TAG, "No Bluetooth Adapter address parameter found");
+ }
}
} else if (Intent.ACTION_SETTING_RESTORED.equals(action)) {
final String name = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
if (Settings.Global.BLUETOOTH_ON.equals(name)) {
// The Bluetooth On state may be changed during system restore.
- final String prevValue = intent.getStringExtra(
- Intent.EXTRA_SETTING_PREVIOUS_VALUE);
- final String newValue = intent.getStringExtra(
- Intent.EXTRA_SETTING_NEW_VALUE);
+ final String prevValue =
+ intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE);
+ final String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
- if (DBG) Slog.d(TAG, "ACTION_SETTING_RESTORED with BLUETOOTH_ON, prevValue=" +
- prevValue + ", newValue=" + newValue);
+ if (DBG) {
+ Slog.d(TAG,
+ "ACTION_SETTING_RESTORED with BLUETOOTH_ON, prevValue=" + prevValue
+ + ", newValue=" + newValue);
+ }
if ((newValue != null) && (prevValue != null) && !prevValue.equals(newValue)) {
Message msg = mHandler.obtainMessage(MESSAGE_RESTORE_USER_SETTING,
- newValue.equals("0") ?
- RESTORE_SETTING_TO_OFF :
- RESTORE_SETTING_TO_ON, 0);
+ newValue.equals("0") ? RESTORE_SETTING_TO_OFF
+ : RESTORE_SETTING_TO_ON, 0);
mHandler.sendMessage(msg);
}
}
@@ -356,8 +365,8 @@
mContext = context;
- mPermissionReviewRequired = context.getResources().getBoolean(
- com.android.internal.R.bool.config_permissionReviewRequired);
+ mPermissionReviewRequired = context.getResources()
+ .getBoolean(com.android.internal.R.bool.config_permissionReviewRequired);
mActiveLogs = new LinkedList<ActiveLog>();
mCrashTimestamps = new LinkedList<Long>();
@@ -389,23 +398,26 @@
loadStoredNameAndAddress();
if (isBluetoothPersistedStateOn()) {
- if (DBG) Slog.d(TAG, "Startup: Bluetooth persisted state is ON.");
+ if (DBG) {
+ Slog.d(TAG, "Startup: Bluetooth persisted state is ON.");
+ }
mEnableExternal = true;
}
- String airplaneModeRadios = Settings.Global.getString(mContentResolver,
- Settings.Global.AIRPLANE_MODE_RADIOS);
- if (airplaneModeRadios == null ||
- airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH)) {
+ String airplaneModeRadios =
+ Settings.Global.getString(mContentResolver, Settings.Global.AIRPLANE_MODE_RADIOS);
+ if (airplaneModeRadios == null || airplaneModeRadios.contains(
+ Settings.Global.RADIO_BLUETOOTH)) {
mContentResolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON),
- true, mAirplaneModeObserver);
+ Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
+ mAirplaneModeObserver);
}
int systemUiUid = -1;
try {
- systemUiUid = mContext.getPackageManager().getPackageUidAsUser("com.android.systemui",
- PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
+ systemUiUid = mContext.getPackageManager()
+ .getPackageUidAsUser("com.android.systemui", PackageManager.MATCH_SYSTEM_ONLY,
+ UserHandle.USER_SYSTEM);
} catch (PackageManager.NameNotFoundException e) {
// Some platforms, such as wearables do not have a system ui.
Slog.w(TAG, "Unable to resolve SystemUI's UID.", e);
@@ -416,7 +428,7 @@
/**
* Returns true if airplane mode is currently on
*/
- private final boolean isAirplaneModeOn() {
+ private boolean isAirplaneModeOn() {
return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
}
@@ -424,31 +436,32 @@
/**
* Returns true if the Bluetooth saved state is "on"
*/
- private final boolean isBluetoothPersistedStateOn() {
- int state = Settings.Global.getInt(mContentResolver,
- Settings.Global.BLUETOOTH_ON, -1);
- if (DBG) Slog.d(TAG, "Bluetooth persisted state: " + state);
+ private boolean isBluetoothPersistedStateOn() {
+ int state = Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON, -1);
+ if (DBG) {
+ Slog.d(TAG, "Bluetooth persisted state: " + state);
+ }
return state != BLUETOOTH_OFF;
}
/**
* Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH
*/
- private final boolean isBluetoothPersistedStateOnBluetooth() {
- return Settings.Global.getInt(mContentResolver,
- Settings.Global.BLUETOOTH_ON, BLUETOOTH_ON_BLUETOOTH) == BLUETOOTH_ON_BLUETOOTH;
+ private boolean isBluetoothPersistedStateOnBluetooth() {
+ return Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON,
+ BLUETOOTH_ON_BLUETOOTH) == BLUETOOTH_ON_BLUETOOTH;
}
/**
* Save the Bluetooth on/off state
*/
private void persistBluetoothSetting(int value) {
- if (DBG) Slog.d(TAG, "Persisting Bluetooth Setting: " + value);
+ if (DBG) {
+ Slog.d(TAG, "Persisting Bluetooth Setting: " + value);
+ }
// waive WRITE_SECURE_SETTINGS permission check
long callingIdentity = Binder.clearCallingIdentity();
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.BLUETOOTH_ON,
- value);
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.BLUETOOTH_ON, value);
Binder.restoreCallingIdentity(callingIdentity);
}
@@ -458,7 +471,7 @@
* @return
*/
private boolean isNameAndAddressSet() {
- return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
+ return mName != null && mAddress != null && mName.length() > 0 && mAddress.length() > 0;
}
/**
@@ -466,17 +479,24 @@
* in the local cache
*/
private void loadStoredNameAndAddress() {
- if (DBG) Slog.d(TAG, "Loading stored name and address");
- if (mContext.getResources().getBoolean
- (com.android.internal.R.bool.config_bluetooth_address_validation) &&
- Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
+ if (DBG) {
+ Slog.d(TAG, "Loading stored name and address");
+ }
+ if (mContext.getResources()
+ .getBoolean(com.android.internal.R.bool.config_bluetooth_address_validation)
+ && Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0)
+ == 0) {
// if the valid flag is not set, don't load the address and name
- if (DBG) Slog.d(TAG, "invalid bluetooth name and address stored");
+ if (DBG) {
+ Slog.d(TAG, "invalid bluetooth name and address stored");
+ }
return;
}
mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
- if (DBG) Slog.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
+ if (DBG) {
+ Slog.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
+ }
}
/**
@@ -489,15 +509,20 @@
if (name != null) {
Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
mName = name;
- if (DBG) Slog.d(TAG,"Stored Bluetooth name: " +
- Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
+ if (DBG) {
+ Slog.d(TAG, "Stored Bluetooth name: " + Settings.Secure.getString(mContentResolver,
+ SECURE_SETTINGS_BLUETOOTH_NAME));
+ }
}
if (address != null) {
Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
- mAddress=address;
- if (DBG) Slog.d(TAG,"Stored Bluetoothaddress: " +
- Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
+ mAddress = address;
+ if (DBG) {
+ Slog.d(TAG,
+ "Stored Bluetoothaddress: " + Settings.Secure.getString(mContentResolver,
+ SECURE_SETTINGS_BLUETOOTH_ADDRESS));
+ }
}
if ((name != null) && (address != null)) {
@@ -505,7 +530,7 @@
}
}
- public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
+ public IBluetooth registerAdapter(IBluetoothManagerCallback callback) {
if (callback == null) {
Slog.w(TAG, "Callback is null in registerAdapter");
return null;
@@ -522,19 +547,17 @@
Slog.w(TAG, "Callback is null in unregisterAdapter");
return;
}
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
- "Need BLUETOOTH permission");
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
msg.obj = callback;
mHandler.sendMessage(msg);
}
public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
- "Need BLUETOOTH permission");
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
if (callback == null) {
- Slog.w(TAG, "registerStateChangeCallback: Callback is null!");
- return;
+ Slog.w(TAG, "registerStateChangeCallback: Callback is null!");
+ return;
}
Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
msg.obj = callback;
@@ -542,11 +565,10 @@
}
public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
- "Need BLUETOOTH permission");
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
if (callback == null) {
- Slog.w(TAG, "unregisterStateChangeCallback: Callback is null!");
- return;
+ Slog.w(TAG, "unregisterStateChangeCallback: Callback is null!");
+ return;
}
Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
msg.obj = callback;
@@ -554,15 +576,16 @@
}
public boolean isEnabled() {
- if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
- (!checkIfCallerIsForegroundUser())) {
- Slog.w(TAG,"isEnabled(): not allowed for non-active and non system user");
+ if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) {
+ Slog.w(TAG, "isEnabled(): not allowed for non-active and non system user");
return false;
}
try {
mBluetoothLock.readLock().lock();
- if (mBluetooth != null) return mBluetooth.isEnabled();
+ if (mBluetooth != null) {
+ return mBluetooth.isEnabled();
+ }
} catch (RemoteException e) {
Slog.e(TAG, "isEnabled()", e);
} finally {
@@ -572,15 +595,16 @@
}
public int getState() {
- if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
- (!checkIfCallerIsForegroundUser())) {
+ if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) {
Slog.w(TAG, "getState(): report OFF for non-active and non system user");
return BluetoothAdapter.STATE_OFF;
}
try {
mBluetoothLock.readLock().lock();
- if (mBluetooth != null) return mBluetooth.getState();
+ if (mBluetooth != null) {
+ return mBluetooth.getState();
+ }
} catch (RemoteException e) {
Slog.e(TAG, "getState()", e);
} finally {
@@ -592,26 +616,29 @@
class ClientDeathRecipient implements IBinder.DeathRecipient {
private String mPackageName;
- public ClientDeathRecipient(String packageName) {
+ ClientDeathRecipient(String packageName) {
mPackageName = packageName;
}
public void binderDied() {
- if (DBG) Slog.d(TAG, "Binder is dead - unregister " + mPackageName);
- if (isBleAppPresent()) {
- // Nothing to do, another app is here.
- return;
+ if (DBG) {
+ Slog.d(TAG, "Binder is dead - unregister " + mPackageName);
}
- if (DBG) Slog.d(TAG, "Disabling LE only mode after application crash");
+ if (isBleAppPresent()) {
+ // Nothing to do, another app is here.
+ return;
+ }
+ if (DBG) {
+ Slog.d(TAG, "Disabling LE only mode after application crash");
+ }
try {
mBluetoothLock.readLock().lock();
- if (mBluetooth != null &&
- mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
+ if (mBluetooth != null && mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
mEnable = false;
mBluetooth.onBrEdrDown();
}
} catch (RemoteException e) {
- Slog.e(TAG,"Unable to call onBrEdrDown", e);
+ Slog.e(TAG, "Unable to call onBrEdrDown", e);
} finally {
mBluetoothLock.readLock().unlock();
}
@@ -641,15 +668,17 @@
@Override
public void onChange(boolean selfChange) {
if (isBleScanAlwaysAvailable()) {
- // Nothing to do
- return;
+ // Nothing to do
+ return;
}
// BLE scan is not available.
disableBleScanMode();
clearBleApps();
try {
mBluetoothLock.readLock().lock();
- if (mBluetooth != null) mBluetooth.onBrEdrDown();
+ if (mBluetooth != null) {
+ mBluetooth.onBrEdrDown();
+ }
} catch (RemoteException e) {
Slog.e(TAG, "error when disabling bluetooth", e);
} finally {
@@ -659,8 +688,8 @@
};
mContentResolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE),
- false, contentObserver);
+ Settings.Global.getUriFor(Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE), false,
+ contentObserver);
}
// Disable ble scan only mode.
@@ -668,7 +697,9 @@
try {
mBluetoothLock.writeLock().lock();
if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) {
- if (DBG) Slog.d(TAG, "Reseting the mEnable flag for clean disable");
+ if (DBG) {
+ Slog.d(TAG, "Reseting the mEnable flag for clean disable");
+ }
mEnable = false;
}
} catch (RemoteException e) {
@@ -688,15 +719,21 @@
throw new IllegalArgumentException("BLE app (" + packageName + ") already dead!");
}
mBleApps.put(token, deathRec);
- if (DBG) Slog.d(TAG, "Registered for death of " + packageName);
+ if (DBG) {
+ Slog.d(TAG, "Registered for death of " + packageName);
+ }
} else if (!enable && r != null) {
// Unregister death recipient as the app goes away.
token.unlinkToDeath(r, 0);
mBleApps.remove(token);
- if (DBG) Slog.d(TAG, "Unregistered for death of " + packageName);
+ if (DBG) {
+ Slog.d(TAG, "Unregistered for death of " + packageName);
+ }
}
int appCount = mBleApps.size();
- if (DBG) Slog.d(TAG, appCount + " registered Ble Apps");
+ if (DBG) {
+ Slog.d(TAG, appCount + " registered Ble Apps");
+ }
if (appCount == 0 && mEnable) {
disableBleScanMode();
}
@@ -713,7 +750,9 @@
/** @hide */
public boolean isBleAppPresent() {
- if (DBG) Slog.d(TAG, "isBleAppPresent() count: " + mBleApps.size());
+ if (DBG) {
+ Slog.d(TAG, "isBleAppPresent() count: " + mBleApps.size());
+ }
return mBleApps.size() > 0;
}
@@ -721,17 +760,23 @@
* Action taken when GattService is turned on
*/
private void onBluetoothGattServiceUp() {
- if (DBG) Slog.d(TAG,"BluetoothGatt Service is Up");
+ if (DBG) {
+ Slog.d(TAG, "BluetoothGatt Service is Up");
+ }
try {
mBluetoothLock.readLock().lock();
if (mBluetooth == null) {
- if (DBG) Slog.w(TAG, "onBluetoothServiceUp: mBluetooth is null!");
+ if (DBG) {
+ Slog.w(TAG, "onBluetoothServiceUp: mBluetooth is null!");
+ }
return;
}
int st = mBluetooth.getState();
if (st != BluetoothAdapter.STATE_BLE_ON) {
- if (DBG) Slog.v(TAG, "onBluetoothServiceUp: state isn't BLE_ON: " +
- BluetoothAdapter.nameForState(st));
+ if (DBG) {
+ Slog.v(TAG, "onBluetoothServiceUp: state isn't BLE_ON: "
+ + BluetoothAdapter.nameForState(st));
+ }
return;
}
if (isBluetoothPersistedStateOnBluetooth() || !isBleAppPresent()) {
@@ -740,7 +785,7 @@
persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
}
} catch (RemoteException e) {
- Slog.e(TAG,"Unable to call onServiceUp", e);
+ Slog.e(TAG, "Unable to call onServiceUp", e);
} finally {
mBluetoothLock.readLock().unlock();
}
@@ -751,7 +796,9 @@
* and turn off all service and stack if no LE app needs it
*/
private void sendBrEdrDownCallback() {
- if (DBG) Slog.d(TAG,"Calling sendBrEdrDownCallback callbacks");
+ if (DBG) {
+ Slog.d(TAG, "Calling sendBrEdrDownCallback callbacks");
+ }
if (mBluetooth == null) {
Slog.w(TAG, "Bluetooth handle is null");
@@ -768,7 +815,9 @@
} else {
try {
mBluetoothLock.readLock().lock();
- if (mBluetooth != null) mBluetooth.onBrEdrDown();
+ if (mBluetooth != null) {
+ mBluetooth.onBrEdrDown();
+ }
} catch (RemoteException e) {
Slog.e(TAG, "Call to onBrEdrDown() failed.", e);
} finally {
@@ -778,8 +827,7 @@
}
- public boolean enableNoAutoConnect(String packageName)
- {
+ public boolean enableNoAutoConnect(String packageName) {
if (isBluetoothDisallowed()) {
if (DBG) {
Slog.d(TAG, "enableNoAutoConnect(): not enabling - bluetooth disallowed");
@@ -788,11 +836,11 @@
}
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH ADMIN permission");
+ "Need BLUETOOTH ADMIN permission");
if (DBG) {
- Slog.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
- " mBinding = " + mBinding);
+ Slog.d(TAG, "enableNoAutoConnect(): mBluetooth =" + mBluetooth + " mBinding = "
+ + mBinding);
}
int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
@@ -800,7 +848,7 @@
throw new SecurityException("no permission to enable Bluetooth quietly");
}
- synchronized(mReceiver) {
+ synchronized (mReceiver) {
mQuietEnableExternal = true;
mEnableExternal = true;
sendEnableMsg(true, packageName);
@@ -814,7 +862,7 @@
if (isBluetoothDisallowed()) {
if (DBG) {
- Slog.d(TAG,"enable(): not enabling - bluetooth disallowed");
+ Slog.d(TAG, "enable(): not enabling - bluetooth disallowed");
}
return false;
}
@@ -828,26 +876,26 @@
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
- if (!isEnabled() && mPermissionReviewRequired
- && startConsentUiIfNeeded(packageName, callingUid,
- BluetoothAdapter.ACTION_REQUEST_ENABLE)) {
+ if (!isEnabled() && mPermissionReviewRequired && startConsentUiIfNeeded(packageName,
+ callingUid, BluetoothAdapter.ACTION_REQUEST_ENABLE)) {
return false;
}
}
if (DBG) {
- Slog.d(TAG,"enable(" + packageName + "): mBluetooth =" + mBluetooth +
- " mBinding = " + mBinding + " mState = " +
- BluetoothAdapter.nameForState(mState));
+ Slog.d(TAG, "enable(" + packageName + "): mBluetooth =" + mBluetooth + " mBinding = "
+ + mBinding + " mState = " + BluetoothAdapter.nameForState(mState));
}
- synchronized(mReceiver) {
+ synchronized (mReceiver) {
mQuietEnableExternal = false;
mEnableExternal = true;
// waive WRITE_SECURE_SETTINGS permission check
sendEnableMsg(false, packageName);
}
- if (DBG) Slog.d(TAG, "enable returning");
+ if (DBG) {
+ Slog.d(TAG, "enable returning");
+ }
return true;
}
@@ -864,19 +912,17 @@
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
- if (isEnabled() && mPermissionReviewRequired
- && startConsentUiIfNeeded(packageName, callingUid,
- BluetoothAdapter.ACTION_REQUEST_DISABLE)) {
+ if (isEnabled() && mPermissionReviewRequired && startConsentUiIfNeeded(packageName,
+ callingUid, BluetoothAdapter.ACTION_REQUEST_DISABLE)) {
return false;
}
}
if (DBG) {
- Slog.d(TAG,"disable(): mBluetooth = " + mBluetooth +
- " mBinding = " + mBinding);
+ Slog.d(TAG, "disable(): mBluetooth = " + mBluetooth + " mBinding = " + mBinding);
}
- synchronized(mReceiver) {
+ synchronized (mReceiver) {
if (persist) {
persistBluetoothSetting(BLUETOOTH_OFF);
}
@@ -886,8 +932,8 @@
return true;
}
- private boolean startConsentUiIfNeeded(String packageName,
- int callingUid, String intentAction) throws RemoteException {
+ private boolean startConsentUiIfNeeded(String packageName, int callingUid, String intentAction)
+ throws RemoteException {
try {
// Validate the package only if we are going to use it
ApplicationInfo applicationInfo = mContext.getPackageManager()
@@ -895,14 +941,13 @@
PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
UserHandle.getUserId(callingUid));
if (applicationInfo.uid != callingUid) {
- throw new SecurityException("Package " + callingUid
- + " not in uid " + callingUid);
+ throw new SecurityException("Package " + callingUid + " not in uid " + callingUid);
}
Intent intent = new Intent(intentAction);
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ intent.setFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
try {
mContext.startActivity(intent);
} catch (ActivityNotFoundException e) {
@@ -918,13 +963,15 @@
public void unbindAndFinish() {
if (DBG) {
- Slog.d(TAG,"unbindAndFinish(): " + mBluetooth +
- " mBinding = " + mBinding + " mUnbinding = " + mUnbinding);
+ Slog.d(TAG, "unbindAndFinish(): " + mBluetooth + " mBinding = " + mBinding
+ + " mUnbinding = " + mUnbinding);
}
try {
mBluetoothLock.writeLock().lock();
- if (mUnbinding) return;
+ if (mUnbinding) {
+ return;
+ }
mUnbinding = true;
mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE);
@@ -933,7 +980,7 @@
try {
mBluetooth.unregisterCallback(mBluetoothCallback);
} catch (RemoteException re) {
- Slog.e(TAG, "Unable to unregister BluetoothCallback",re);
+ Slog.e(TAG, "Unable to unregister BluetoothCallback", re);
}
mBluetoothBinder = null;
mBluetooth = null;
@@ -959,8 +1006,8 @@
IBluetoothProfileServiceConnection proxy) {
if (!mEnable) {
if (DBG) {
- Slog.d(TAG, "Trying to bind to profile: " + bluetoothProfile +
- ", while Bluetooth was disabled");
+ Slog.d(TAG, "Trying to bind to profile: " + bluetoothProfile
+ + ", while Bluetooth was disabled");
}
return false;
}
@@ -968,15 +1015,19 @@
ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
if (psc == null) {
if (DBG) {
- Slog.d(TAG, "Creating new ProfileServiceConnections object for"
- + " profile: " + bluetoothProfile);
+ Slog.d(TAG, "Creating new ProfileServiceConnections object for" + " profile: "
+ + bluetoothProfile);
}
- if (bluetoothProfile != BluetoothProfile.HEADSET) return false;
+ if (bluetoothProfile != BluetoothProfile.HEADSET) {
+ return false;
+ }
Intent intent = new Intent(IBluetoothHeadset.class.getName());
psc = new ProfileServiceConnections(intent);
- if (!psc.bindService()) return false;
+ if (!psc.bindService()) {
+ return false;
+ }
mProfileServices.put(new Integer(bluetoothProfile), psc);
}
@@ -1022,7 +1073,9 @@
* PHASE_SYSTEM_SERVICES_READY.
*/
public void handleOnBootPhase() {
- if (DBG) Slog.d(TAG, "Bluetooth boot completed");
+ if (DBG) {
+ Slog.d(TAG, "Bluetooth boot completed");
+ }
UserManagerInternal userManagerInternal =
LocalServices.getService(UserManagerInternal.class);
userManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
@@ -1031,10 +1084,14 @@
return;
}
if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
- if (DBG) Slog.d(TAG, "Auto-enabling Bluetooth.");
+ if (DBG) {
+ Slog.d(TAG, "Auto-enabling Bluetooth.");
+ }
sendEnableMsg(mQuietEnableExternal, REASON_SYSTEM_BOOT);
} else if (!isNameAndAddressSet()) {
- if (DBG) Slog.d(TAG, "Getting adapter name and address");
+ if (DBG) {
+ Slog.d(TAG, "Getting adapter name and address");
+ }
Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
mHandler.sendMessage(getMsg);
}
@@ -1044,7 +1101,9 @@
* Called when switching to a different foreground user.
*/
public void handleOnSwitchUser(int userHandle) {
- if (DBG) Slog.d(TAG, "User " + userHandle + " switched");
+ if (DBG) {
+ Slog.d(TAG, "User " + userHandle + " switched");
+ }
mHandler.obtainMessage(MESSAGE_USER_SWITCHED, userHandle, 0).sendToTarget();
}
@@ -1052,7 +1111,9 @@
* Called when user is unlocked.
*/
public void handleOnUnlockUser(int userHandle) {
- if (DBG) Slog.d(TAG, "User " + userHandle + " unlocked");
+ if (DBG) {
+ Slog.d(TAG, "User " + userHandle + " unlocked");
+ }
mHandler.obtainMessage(MESSAGE_USER_UNLOCKED, userHandle, 0).sendToTarget();
}
@@ -1060,10 +1121,10 @@
* This class manages the clients connected to a given ProfileService
* and maintains the connection with that service.
*/
- final private class ProfileServiceConnections implements ServiceConnection,
- IBinder.DeathRecipient {
+ private final class ProfileServiceConnections
+ implements ServiceConnection, IBinder.DeathRecipient {
final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies =
- new RemoteCallbackList <IBluetoothProfileServiceConnection>();
+ new RemoteCallbackList<IBluetoothProfileServiceConnection>();
IBinder mService;
ComponentName mClassName;
Intent mIntent;
@@ -1076,8 +1137,8 @@
}
private boolean bindService() {
- if (mIntent != null && mService == null &&
- doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) {
+ if (mIntent != null && mService == null && doBind(mIntent, this, 0,
+ UserHandle.CURRENT_OR_SELF)) {
Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
msg.obj = this;
mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
@@ -1090,7 +1151,7 @@
private void addProxy(IBluetoothProfileServiceConnection proxy) {
mProxies.register(proxy);
if (mService != null) {
- try{
+ try {
proxy.onServiceConnected(mClassName, mService);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to connect to proxy", e);
@@ -1158,7 +1219,9 @@
@Override
public void onServiceDisconnected(ComponentName className) {
- if (mService == null) return;
+ if (mService == null) {
+ return;
+ }
mService.unlinkToDeath(this, 0);
mService = null;
mClassName = null;
@@ -1187,8 +1250,7 @@
@Override
public void binderDied() {
if (DBG) {
- Slog.w(TAG, "Profile service for profile: " + mClassName
- + " died.");
+ Slog.w(TAG, "Profile service for profile: " + mClassName + " died.");
}
onServiceDisconnected(mClassName);
// Trigger rebind
@@ -1201,12 +1263,15 @@
private void sendBluetoothStateCallback(boolean isUp) {
try {
int n = mStateChangeCallbacks.beginBroadcast();
- if (DBG) Slog.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
- for (int i=0; i <n;i++) {
+ if (DBG) {
+ Slog.d(TAG, "Broadcasting onBluetoothStateChange(" + isUp + ") to " + n
+ + " receivers.");
+ }
+ for (int i = 0; i < n; i++) {
try {
mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
} catch (RemoteException e) {
- Slog.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
+ Slog.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i, e);
}
}
} finally {
@@ -1220,11 +1285,11 @@
private void sendBluetoothServiceUpCallback() {
try {
int n = mCallbacks.beginBroadcast();
- Slog.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
- for (int i=0; i <n;i++) {
+ Slog.d(TAG, "Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
+ for (int i = 0; i < n; i++) {
try {
mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
- } catch (RemoteException e) {
+ } catch (RemoteException e) {
Slog.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
}
}
@@ -1232,17 +1297,18 @@
mCallbacks.finishBroadcast();
}
}
+
/**
* Inform BluetoothAdapter instances that Adapter service is down
*/
private void sendBluetoothServiceDownCallback() {
try {
int n = mCallbacks.beginBroadcast();
- Slog.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
- for (int i=0; i <n;i++) {
+ Slog.d(TAG, "Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
+ for (int i = 0; i < n; i++) {
try {
mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
- } catch (RemoteException e) {
+ } catch (RemoteException e) {
Slog.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
}
}
@@ -1252,12 +1318,10 @@
}
public String getAddress() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
- "Need BLUETOOTH permission");
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
- (!checkIfCallerIsForegroundUser())) {
- Slog.w(TAG,"getAddress(): not allowed for non-active and non system user");
+ if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) {
+ Slog.w(TAG, "getAddress(): not allowed for non-active and non system user");
return null;
}
@@ -1268,9 +1332,13 @@
try {
mBluetoothLock.readLock().lock();
- if (mBluetooth != null) return mBluetooth.getAddress();
+ if (mBluetooth != null) {
+ return mBluetooth.getAddress();
+ }
} catch (RemoteException e) {
- Slog.e(TAG, "getAddress(): Unable to retrieve address remotely. Returning cached address", e);
+ Slog.e(TAG,
+ "getAddress(): Unable to retrieve address remotely. Returning cached address",
+ e);
} finally {
mBluetoothLock.readLock().unlock();
}
@@ -1282,18 +1350,18 @@
}
public String getName() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
- "Need BLUETOOTH permission");
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
- (!checkIfCallerIsForegroundUser())) {
- Slog.w(TAG,"getName(): not allowed for non-active and non system user");
+ if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) {
+ Slog.w(TAG, "getName(): not allowed for non-active and non system user");
return null;
}
try {
mBluetoothLock.readLock().lock();
- if (mBluetooth != null) return mBluetooth.getName();
+ if (mBluetooth != null) {
+ return mBluetooth.getName();
+ }
} catch (RemoteException e) {
Slog.e(TAG, "getName(): Unable to retrieve name remotely. Returning cached name", e);
} finally {
@@ -1309,7 +1377,9 @@
private class BluetoothServiceConnection implements ServiceConnection {
public void onServiceConnected(ComponentName componentName, IBinder service) {
String name = componentName.getClassName();
- if (DBG) Slog.d(TAG, "BluetoothServiceConnection: " + name);
+ if (DBG) {
+ Slog.d(TAG, "BluetoothServiceConnection: " + name);
+ }
Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
if (name.equals("com.android.bluetooth.btservice.AdapterService")) {
msg.arg1 = SERVICE_IBLUETOOTH;
@@ -1326,7 +1396,9 @@
public void onServiceDisconnected(ComponentName componentName) {
// Called if we unexpectedly disconnect.
String name = componentName.getClassName();
- if (DBG) Slog.d(TAG, "BluetoothServiceConnection, disconnected: " + name);
+ if (DBG) {
+ Slog.d(TAG, "BluetoothServiceConnection, disconnected: " + name);
+ }
Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
if (name.equals("com.android.bluetooth.btservice.AdapterService")) {
msg.arg1 = SERVICE_IBLUETOOTH;
@@ -1345,7 +1417,7 @@
private class BluetoothHandler extends Handler {
boolean mGetNameAddressOnly = false;
- public BluetoothHandler(Looper looper) {
+ BluetoothHandler(Looper looper) {
super(looper);
}
@@ -1353,26 +1425,29 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_GET_NAME_AND_ADDRESS:
- if (DBG) Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS");
+ if (DBG) {
+ Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS");
+ }
try {
mBluetoothLock.writeLock().lock();
if ((mBluetooth == null) && (!mBinding)) {
- if (DBG) Slog.d(TAG, "Binding to service to get name and address");
+ if (DBG) {
+ Slog.d(TAG, "Binding to service to get name and address");
+ }
mGetNameAddressOnly = true;
Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS);
Intent i = new Intent(IBluetooth.class.getName());
if (!doBind(i, mConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
- UserHandle.CURRENT)) {
+ Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
+ UserHandle.CURRENT)) {
mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
} else {
mBinding = true;
}
} else if (mBluetooth != null) {
try {
- storeNameAndAddress(mBluetooth.getName(),
- mBluetooth.getAddress());
+ storeNameAndAddress(mBluetooth.getName(), mBluetooth.getAddress());
} catch (RemoteException re) {
Slog.e(TAG, "Unable to grab names", re);
}
@@ -1431,15 +1506,16 @@
// on the order of (2 * SERVICE_RESTART_TIME_MS).
//
waitForOnOff(false, true);
- Message restartMsg = mHandler.obtainMessage(
- MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mHandler.sendMessageDelayed(restartMsg,
- 2 * SERVICE_RESTART_TIME_MS);
+ Message restartMsg =
+ mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
+ mHandler.sendMessageDelayed(restartMsg, 2 * SERVICE_RESTART_TIME_MS);
}
break;
case MESSAGE_DISABLE:
- if (DBG) Slog.d(TAG, "MESSAGE_DISABLE: mBluetooth = " + mBluetooth);
+ if (DBG) {
+ Slog.d(TAG, "MESSAGE_DISABLE: mBluetooth = " + mBluetooth);
+ }
mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
if (mEnable && mBluetooth != null) {
waitForOnOff(true, false);
@@ -1455,45 +1531,45 @@
case MESSAGE_RESTORE_USER_SETTING:
try {
if ((msg.arg1 == RESTORE_SETTING_TO_OFF) && mEnable) {
- if (DBG) Slog.d(TAG, "Restore Bluetooth state to disabled");
+ if (DBG) {
+ Slog.d(TAG, "Restore Bluetooth state to disabled");
+ }
disable(REASON_RESTORE_USER_SETTING, true);
} else if ((msg.arg1 == RESTORE_SETTING_TO_ON) && !mEnable) {
- if (DBG) Slog.d(TAG, "Restore Bluetooth state to enabled");
+ if (DBG) {
+ Slog.d(TAG, "Restore Bluetooth state to enabled");
+ }
enable(REASON_RESTORE_USER_SETTING);
}
} catch (RemoteException e) {
- Slog.e(TAG,"Unable to change Bluetooth On setting", e);
+ Slog.e(TAG, "Unable to change Bluetooth On setting", e);
}
break;
- case MESSAGE_REGISTER_ADAPTER:
- {
+ case MESSAGE_REGISTER_ADAPTER: {
IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
mCallbacks.register(callback);
break;
}
- case MESSAGE_UNREGISTER_ADAPTER:
- {
+ case MESSAGE_UNREGISTER_ADAPTER: {
IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
mCallbacks.unregister(callback);
break;
}
- case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
- {
- IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
+ case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: {
+ IBluetoothStateChangeCallback callback =
+ (IBluetoothStateChangeCallback) msg.obj;
mStateChangeCallbacks.register(callback);
break;
}
- case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
- {
- IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
+ case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK: {
+ IBluetoothStateChangeCallback callback =
+ (IBluetoothStateChangeCallback) msg.obj;
mStateChangeCallbacks.unregister(callback);
break;
}
- case MESSAGE_ADD_PROXY_DELAYED:
- {
- ProfileServiceConnections psc = mProfileServices.get(
- new Integer(msg.arg1));
+ case MESSAGE_ADD_PROXY_DELAYED: {
+ ProfileServiceConnections psc = mProfileServices.get(new Integer(msg.arg1));
if (psc == null) {
break;
}
@@ -1502,8 +1578,7 @@
psc.addProxy(proxy);
break;
}
- case MESSAGE_BIND_PROFILE_SERVICE:
- {
+ case MESSAGE_BIND_PROFILE_SERVICE: {
ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj;
removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj);
if (psc == null) {
@@ -1512,16 +1587,17 @@
psc.bindService();
break;
}
- case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
- {
- if (DBG) Slog.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
+ case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: {
+ if (DBG) {
+ Slog.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
+ }
IBinder service = (IBinder) msg.obj;
try {
mBluetoothLock.writeLock().lock();
if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
- mBluetoothGatt = IBluetoothGatt.Stub
- .asInterface(Binder.allowBlocking(service));
+ mBluetoothGatt =
+ IBluetoothGatt.Stub.asInterface(Binder.allowBlocking(service));
onBluetoothGattServiceUp();
break;
} // else must be SERVICE_IBLUETOOTH
@@ -1536,31 +1612,33 @@
if (!isNameAndAddressSet()) {
Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
mHandler.sendMessage(getMsg);
- if (mGetNameAddressOnly) return;
+ if (mGetNameAddressOnly) {
+ return;
+ }
}
//Register callback object
try {
mBluetooth.registerCallback(mBluetoothCallback);
} catch (RemoteException re) {
- Slog.e(TAG, "Unable to register BluetoothCallback",re);
+ Slog.e(TAG, "Unable to register BluetoothCallback", re);
}
//Inform BluetoothAdapter instances that service is up
sendBluetoothServiceUpCallback();
//Do enable request
try {
- if (mQuietEnable == false) {
+ if (mQuietEnable) {
if (!mBluetooth.enable()) {
- Slog.e(TAG,"IBluetooth.enable() returned false");
+ Slog.e(TAG, "IBluetooth.enable() returned false");
}
} else {
if (!mBluetooth.enableNoAutoConnect()) {
- Slog.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
+ Slog.e(TAG, "IBluetooth.enableNoAutoConnect() returned false");
}
}
} catch (RemoteException e) {
- Slog.e(TAG,"Unable to call enable()",e);
+ Slog.e(TAG, "Unable to call enable()", e);
}
} finally {
mBluetoothLock.writeLock().unlock();
@@ -1573,43 +1651,42 @@
}
break;
}
- case MESSAGE_BLUETOOTH_STATE_CHANGE:
- {
+ case MESSAGE_BLUETOOTH_STATE_CHANGE: {
int prevState = msg.arg1;
int newState = msg.arg2;
if (DBG) {
- Slog.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: " + BluetoothAdapter.nameForState(prevState) + " > " +
- BluetoothAdapter.nameForState(newState));
+ Slog.d(TAG,
+ "MESSAGE_BLUETOOTH_STATE_CHANGE: " + BluetoothAdapter.nameForState(
+ prevState) + " > " + BluetoothAdapter.nameForState(
+ newState));
}
mState = newState;
bluetoothStateChangeHandler(prevState, newState);
// handle error state transition case from TURNING_ON to OFF
// unbind and rebind bluetooth service and enable bluetooth
- if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) &&
- (newState == BluetoothAdapter.STATE_OFF) &&
- (mBluetooth != null) && mEnable) {
+ if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) && (newState
+ == BluetoothAdapter.STATE_OFF) && (mBluetooth != null) && mEnable) {
recoverBluetoothServiceFromError(false);
}
- if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
- (newState == BluetoothAdapter.STATE_BLE_ON) &&
- (mBluetooth != null) && mEnable) {
+ if ((prevState == BluetoothAdapter.STATE_TURNING_ON) && (newState
+ == BluetoothAdapter.STATE_BLE_ON) && (mBluetooth != null) && mEnable) {
recoverBluetoothServiceFromError(true);
}
// If we tried to enable BT while BT was in the process of shutting down,
// wait for the BT process to fully tear down and then force a restart
// here. This is a bit of a hack (b/29363429).
- if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_OFF) &&
- (newState == BluetoothAdapter.STATE_OFF)) {
+ if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_OFF) && (newState
+ == BluetoothAdapter.STATE_OFF)) {
if (mEnable) {
Slog.d(TAG, "Entering STATE_OFF but mEnabled is true; restarting.");
waitForOnOff(false, true);
- Message restartMsg = mHandler.obtainMessage(
- MESSAGE_RESTART_BLUETOOTH_SERVICE);
+ Message restartMsg =
+ mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
mHandler.sendMessageDelayed(restartMsg, 2 * SERVICE_RESTART_TIME_MS);
}
}
- if (newState == BluetoothAdapter.STATE_ON ||
- newState == BluetoothAdapter.STATE_BLE_ON) {
+ if (newState == BluetoothAdapter.STATE_ON
+ || newState == BluetoothAdapter.STATE_BLE_ON) {
// bluetooth is working, reset the counter
if (mErrorRecoveryRetryCounter != 0) {
Slog.w(TAG, "bluetooth is recovered from error");
@@ -1618,14 +1695,15 @@
}
break;
}
- case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
- {
+ case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: {
Slog.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED(" + msg.arg1 + ")");
try {
mBluetoothLock.writeLock().lock();
if (msg.arg1 == SERVICE_IBLUETOOTH) {
// if service is unbinded already, do nothing and return
- if (mBluetooth == null) break;
+ if (mBluetooth == null) {
+ break;
+ }
mBluetooth = null;
} else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
mBluetoothGatt = null;
@@ -1644,33 +1722,31 @@
if (mEnable) {
mEnable = false;
// Send a Bluetooth Restart message
- Message restartMsg = mHandler.obtainMessage(
- MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mHandler.sendMessageDelayed(restartMsg,
- SERVICE_RESTART_TIME_MS);
+ Message restartMsg =
+ mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
+ mHandler.sendMessageDelayed(restartMsg, SERVICE_RESTART_TIME_MS);
}
sendBluetoothServiceDownCallback();
// Send BT state broadcast to update
// the BT icon correctly
- if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
- (mState == BluetoothAdapter.STATE_ON)) {
+ if ((mState == BluetoothAdapter.STATE_TURNING_ON) || (mState
+ == BluetoothAdapter.STATE_ON)) {
bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
- BluetoothAdapter.STATE_TURNING_OFF);
+ BluetoothAdapter.STATE_TURNING_OFF);
mState = BluetoothAdapter.STATE_TURNING_OFF;
}
if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
- BluetoothAdapter.STATE_OFF);
+ BluetoothAdapter.STATE_OFF);
}
mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
mState = BluetoothAdapter.STATE_OFF;
break;
}
- case MESSAGE_RESTART_BLUETOOTH_SERVICE:
- {
+ case MESSAGE_RESTART_BLUETOOTH_SERVICE: {
Slog.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE");
/* Enable without persisting the setting as
it doesnt change when IBluetooth
@@ -1687,8 +1763,7 @@
mBluetoothLock.writeLock().unlock();
break;
}
- case MESSAGE_TIMEOUT_UNBIND:
- {
+ case MESSAGE_TIMEOUT_UNBIND: {
Slog.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
mBluetoothLock.writeLock().lock();
mUnbinding = false;
@@ -1697,7 +1772,9 @@
}
case MESSAGE_USER_SWITCHED: {
- if (DBG) Slog.d(TAG, "MESSAGE_USER_SWITCHED");
+ if (DBG) {
+ Slog.d(TAG, "MESSAGE_USER_SWITCHED");
+ }
mHandler.removeMessages(MESSAGE_USER_SWITCHED);
/* disable and enable BT when detect a user switch */
@@ -1735,12 +1812,12 @@
handleDisable();
// Pbap service need receive STATE_TURNING_OFF intent to close
bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
- BluetoothAdapter.STATE_TURNING_OFF);
+ BluetoothAdapter.STATE_TURNING_OFF);
boolean didDisableTimeout = !waitForOnOff(false, true);
bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
- BluetoothAdapter.STATE_OFF);
+ BluetoothAdapter.STATE_OFF);
sendBluetoothServiceDownCallback();
try {
@@ -1785,14 +1862,18 @@
break;
}
case MESSAGE_USER_UNLOCKED: {
- if (DBG) Slog.d(TAG, "MESSAGE_USER_UNLOCKED");
+ if (DBG) {
+ Slog.d(TAG, "MESSAGE_USER_UNLOCKED");
+ }
mHandler.removeMessages(MESSAGE_USER_SWITCHED);
if (mEnable && !mBinding && (mBluetooth == null)) {
// We should be connected, but we gave up for some
// reason; maybe the Bluetooth service wasn't encryption
// aware, so try binding again.
- if (DBG) Slog.d(TAG, "Enabled but not bound; retrying after unlock");
+ if (DBG) {
+ Slog.d(TAG, "Enabled but not bound; retrying after unlock");
+ }
handleEnable(mQuietEnable);
}
}
@@ -1807,10 +1888,10 @@
mBluetoothLock.writeLock().lock();
if ((mBluetooth == null) && (!mBinding)) {
//Start bind timeout and bind
- Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
- mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
+ Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
+ mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS);
Intent i = new Intent(IBluetooth.class.getName());
- if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
+ if (!doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
UserHandle.CURRENT)) {
mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
} else {
@@ -1820,17 +1901,16 @@
//Enable bluetooth
try {
if (!mQuietEnable) {
- if(!mBluetooth.enable()) {
- Slog.e(TAG,"IBluetooth.enable() returned false");
+ if (!mBluetooth.enable()) {
+ Slog.e(TAG, "IBluetooth.enable() returned false");
}
- }
- else {
- if(!mBluetooth.enableNoAutoConnect()) {
- Slog.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
+ } else {
+ if (!mBluetooth.enableNoAutoConnect()) {
+ Slog.e(TAG, "IBluetooth.enableNoAutoConnect() returned false");
}
}
} catch (RemoteException e) {
- Slog.e(TAG,"Unable to call enable()",e);
+ Slog.e(TAG, "Unable to call enable()", e);
}
}
} finally {
@@ -1852,13 +1932,15 @@
try {
mBluetoothLock.readLock().lock();
if (mBluetooth != null) {
- if (DBG) Slog.d(TAG,"Sending off request.");
+ if (DBG) {
+ Slog.d(TAG, "Sending off request.");
+ }
if (!mBluetooth.disable()) {
- Slog.e(TAG,"IBluetooth.disable() returned false");
+ Slog.e(TAG, "IBluetooth.disable() returned false");
}
}
} catch (RemoteException e) {
- Slog.e(TAG,"Unable to call disable()",e);
+ Slog.e(TAG, "Unable to call disable()", e);
} finally {
mBluetoothLock.readLock().unlock();
}
@@ -1876,15 +1958,12 @@
boolean valid = false;
try {
foregroundUser = ActivityManager.getCurrentUser();
- valid = (callingUser == foregroundUser) ||
- parentUser == foregroundUser ||
- callingAppId == Process.NFC_UID ||
- callingAppId == mSystemUiUid;
+ valid = (callingUser == foregroundUser) || parentUser == foregroundUser
+ || callingAppId == Process.NFC_UID || callingAppId == mSystemUiUid;
if (DBG && !valid) {
- Slog.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
- + " callingUser=" + callingUser
- + " parentUser=" + parentUser
- + " foregroundUser=" + foregroundUser);
+ Slog.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid + " callingUser="
+ + callingUser + " parentUser=" + parentUser + " foregroundUser="
+ + foregroundUser);
}
} finally {
Binder.restoreCallingIdentity(callingIdentity);
@@ -1893,8 +1972,11 @@
}
private void sendBleStateChanged(int prevState, int newState) {
- if (DBG) Slog.d(TAG,"Sending BLE State Change: " + BluetoothAdapter.nameForState(prevState) +
- " > " + BluetoothAdapter.nameForState(newState));
+ if (DBG) {
+ Slog.d(TAG,
+ "Sending BLE State Change: " + BluetoothAdapter.nameForState(prevState) + " > "
+ + BluetoothAdapter.nameForState(newState));
+ }
// Send broadcast message to everyone else
Intent intent = new Intent(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
@@ -1909,14 +1991,15 @@
return;
}
// Notify all proxy objects first of adapter state change
- if (newState == BluetoothAdapter.STATE_BLE_ON ||
- newState == BluetoothAdapter.STATE_OFF) {
+ if (newState == BluetoothAdapter.STATE_BLE_ON || newState == BluetoothAdapter.STATE_OFF) {
boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF
- && newState == BluetoothAdapter.STATE_BLE_ON);
+ && newState == BluetoothAdapter.STATE_BLE_ON);
if (newState == BluetoothAdapter.STATE_OFF) {
// If Bluetooth is off, send service down event to proxy objects, and unbind
- if (DBG) Slog.d(TAG, "Bluetooth is complete send Service Down");
+ if (DBG) {
+ Slog.d(TAG, "Bluetooth is complete send Service Down");
+ }
sendBluetoothServiceDownCallback();
unbindAndFinish();
sendBleStateChanged(prevState, newState);
@@ -1925,16 +2008,23 @@
} else if (!intermediate_off) {
// connect to GattService
- if (DBG) Slog.d(TAG, "Bluetooth is in LE only mode");
+ if (DBG) {
+ Slog.d(TAG, "Bluetooth is in LE only mode");
+ }
if (mBluetoothGatt != null) {
- if (DBG) Slog.d(TAG, "Calling BluetoothGattServiceUp");
+ if (DBG) {
+ Slog.d(TAG, "Calling BluetoothGattServiceUp");
+ }
onBluetoothGattServiceUp();
} else {
- if (DBG) Slog.d(TAG, "Binding Bluetooth GATT service");
- if (mContext.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_BLUETOOTH_LE)) {
+ if (DBG) {
+ Slog.d(TAG, "Binding Bluetooth GATT service");
+ }
+ if (mContext.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Intent i = new Intent(IBluetoothGatt.class.getName());
- doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.CURRENT);
+ doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
+ UserHandle.CURRENT);
}
}
sendBleStateChanged(prevState, newState);
@@ -1942,7 +2032,9 @@
isStandardBroadcast = false;
} else if (intermediate_off) {
- if (DBG) Slog.d(TAG, "Intermediate off, back to LE only mode");
+ if (DBG) {
+ Slog.d(TAG, "Intermediate off, back to LE only mode");
+ }
// For LE only mode, broadcast as is
sendBleStateChanged(prevState, newState);
sendBluetoothStateCallback(false); // BT is OFF for general users
@@ -1955,13 +2047,13 @@
sendBluetoothStateCallback(isUp);
sendBleStateChanged(prevState, newState);
- } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON ||
- newState == BluetoothAdapter.STATE_BLE_TURNING_OFF ) {
+ } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON
+ || newState == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
sendBleStateChanged(prevState, newState);
isStandardBroadcast = false;
- } else if (newState == BluetoothAdapter.STATE_TURNING_ON ||
- newState == BluetoothAdapter.STATE_TURNING_OFF) {
+ } else if (newState == BluetoothAdapter.STATE_TURNING_ON
+ || newState == BluetoothAdapter.STATE_TURNING_OFF) {
sendBleStateChanged(prevState, newState);
}
@@ -1988,13 +2080,21 @@
while (i < 10) {
try {
mBluetoothLock.readLock().lock();
- if (mBluetooth == null) break;
+ if (mBluetooth == null) {
+ break;
+ }
if (on) {
- if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
+ if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) {
+ return true;
+ }
} else if (off) {
- if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
+ if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) {
+ return true;
+ }
} else {
- if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
+ if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) {
+ return true;
+ }
}
} catch (RemoteException e) {
Slog.e(TAG, "getState()", e);
@@ -2009,7 +2109,7 @@
}
i++;
}
- Slog.e(TAG,"waitForOnOff time out");
+ Slog.e(TAG, "waitForOnOff time out");
return false;
}
@@ -2019,8 +2119,7 @@
}
private void sendEnableMsg(boolean quietMode, String packageName) {
- mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
- quietMode ? 1 : 0, 0));
+ mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0, 0));
addActiveLog(packageName, true);
mLastEnabledTime = SystemClock.elapsedRealtime();
}
@@ -2035,15 +2134,17 @@
}
private void addCrashLog() {
- synchronized (mCrashTimestamps) {
- if (mCrashTimestamps.size() == CRASH_LOG_MAX_SIZE) mCrashTimestamps.removeFirst();
- mCrashTimestamps.add(System.currentTimeMillis());
- mCrashes++;
- }
+ synchronized (mCrashTimestamps) {
+ if (mCrashTimestamps.size() == CRASH_LOG_MAX_SIZE) {
+ mCrashTimestamps.removeFirst();
+ }
+ mCrashTimestamps.add(System.currentTimeMillis());
+ mCrashes++;
+ }
}
private void recoverBluetoothServiceFromError(boolean clearBle) {
- Slog.e(TAG,"recoverBluetoothServiceFromError");
+ Slog.e(TAG, "recoverBluetoothServiceFromError");
try {
mBluetoothLock.readLock().lock();
if (mBluetooth != null) {
@@ -2082,15 +2183,14 @@
mState = BluetoothAdapter.STATE_OFF;
if (clearBle) {
- clearBleApps();
+ clearBleApps();
}
mEnable = false;
if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) {
// Send a Bluetooth Restart message to reenable bluetooth
- Message restartMsg = mHandler.obtainMessage(
- MESSAGE_RESTART_BLUETOOTH_SERVICE);
+ Message restartMsg = mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS);
} else {
// todo: notify user to power down and power up phone to make bluetooth work.
@@ -2118,9 +2218,9 @@
private void updateOppLauncherComponentState(int userId, boolean bluetoothSharingDisallowed) {
final ComponentName oppLauncherComponent = new ComponentName("com.android.bluetooth",
"com.android.bluetooth.opp.BluetoothOppLauncherActivity");
- final int newState = bluetoothSharingDisallowed
- ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED
- : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+ final int newState =
+ bluetoothSharingDisallowed ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+ : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
try {
final IPackageManager imp = AppGlobals.getPackageManager();
imp.setComponentEnabledSetting(oppLauncherComponent, newState,
@@ -2132,7 +2232,9 @@
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
+ if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) {
+ return;
+ }
String errorMsg = null;
boolean protoOut = (args.length > 0) && args[0].startsWith("--proto");
@@ -2145,36 +2247,33 @@
writer.println(" name: " + mName);
if (mEnable) {
long onDuration = SystemClock.elapsedRealtime() - mLastEnabledTime;
- String onDurationString = String.format("%02d:%02d:%02d.%03d",
- (int)(onDuration / (1000 * 60 * 60)),
- (int)((onDuration / (1000 * 60)) % 60),
- (int)((onDuration / 1000) % 60),
- (int)(onDuration % 1000));
- writer.println(" time since enabled: " + onDurationString + "\n");
+ String onDurationString = String.format(Locale.US, "%02d:%02d:%02d.%03d",
+ (int) (onDuration / (1000 * 60 * 60)),
+ (int) ((onDuration / (1000 * 60)) % 60), (int) ((onDuration / 1000) % 60),
+ (int) (onDuration % 1000));
+ writer.println(" time since enabled: " + onDurationString);
}
if (mActiveLogs.size() == 0) {
- writer.println("Bluetooth never enabled!");
+ writer.println("\nBluetooth never enabled!");
} else {
- writer.println("Enable log:");
+ writer.println("\nEnable log:");
for (ActiveLog log : mActiveLogs) {
writer.println(" " + log);
}
}
- writer.println("Bluetooth crashed " + mCrashes + " time" + (mCrashes == 1 ? "" : "s"));
- if (mCrashes == CRASH_LOG_MAX_SIZE) writer.println("(last " + CRASH_LOG_MAX_SIZE + ")");
+ writer.println(
+ "\nBluetooth crashed " + mCrashes + " time" + (mCrashes == 1 ? "" : "s"));
+ if (mCrashes == CRASH_LOG_MAX_SIZE) {
+ writer.println("(last " + CRASH_LOG_MAX_SIZE + ")");
+ }
for (Long time : mCrashTimestamps) {
- writer.println(" " + timeToLog(time.longValue()));
+ writer.println(" " + timeToLog(time));
}
- String bleAppString = "No BLE Apps registered.";
- if (mBleApps.size() == 1) {
- bleAppString = "1 BLE App registered:";
- } else if (mBleApps.size() > 1) {
- bleAppString = mBleApps.size() + " BLE Apps registered:";
- }
- writer.println("\n" + bleAppString);
+ writer.println("\n" + mBleApps.size() + " BLE app" + (mBleApps.size() == 1 ? "" : "s")
+ + "registered");
for (ClientDeathRecipient app : mBleApps.values()) {
writer.println(" " + app.getPackageName());
}
@@ -2199,7 +2298,9 @@
}
if (errorMsg != null) {
// Silently return if we are extracting metrics in Protobuf format
- if (protoOut) return;
+ if (protoOut) {
+ return;
+ }
writer.println(errorMsg);
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index bccae06..86b0164 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -972,7 +972,10 @@
getNetworkTypeName(networkType), "");
info.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
info.setIsAvailable(true);
- state = new NetworkState(info, new LinkProperties(), new NetworkCapabilities(),
+ final NetworkCapabilities capabilities = new NetworkCapabilities();
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING,
+ !info.isRoaming());
+ state = new NetworkState(info, new LinkProperties(), capabilities,
null, null, null);
}
filterNetworkStateForUid(state, uid, ignoreBlocked);
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 0921a00..4f1e335 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -76,6 +76,7 @@
import android.util.TimeUtils;
import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.AtomicFile;
import com.android.internal.os.BackgroundThread;
@@ -119,7 +120,6 @@
private PowerManagerInternal mLocalPowerManager;
private PowerManager mPowerManager;
private ConnectivityService mConnectivityService;
- private AlarmManagerService.LocalService mLocalAlarmManager;
private INetworkPolicyManager mNetworkPolicyManager;
private SensorManager mSensorManager;
private Sensor mMotionSensor;
@@ -1435,7 +1435,6 @@
mGoingIdleWakeLock.setReferenceCounted(true);
mConnectivityService = (ConnectivityService)ServiceManager.getService(
Context.CONNECTIVITY_SERVICE);
- mLocalAlarmManager = getLocalService(AlarmManagerService.LocalService.class);
mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
mNetworkPolicyManagerInternal = getLocalService(NetworkPolicyManagerInternal.class);
@@ -1500,8 +1499,8 @@
mLocalActivityManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
- mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray);
+ passWhiteListToForceAppStandbyTrackerLocked();
updateInteractivityLocked();
}
updateConnectivityState(null);
@@ -1756,6 +1755,27 @@
}
}
+ void removePowerSaveTempWhitelistAppChecked(String packageName, int userId)
+ throws RemoteException {
+ getContext().enforceCallingPermission(
+ Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
+ "No permission to change device idle whitelist");
+ final int callingUid = Binder.getCallingUid();
+ userId = ActivityManager.getService().handleIncomingUser(
+ Binder.getCallingPid(),
+ callingUid,
+ userId,
+ /*allowAll=*/ false,
+ /*requireFull=*/ false,
+ "removePowerSaveTempWhitelistApp", null);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ removePowerSaveTempWhitelistAppInternal(packageName, userId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
/**
* Adds an app to the temporary whitelist and resets the endTime for granting the
* app an exemption to access network and acquire wakelocks.
@@ -1821,6 +1841,32 @@
}
}
+ /**
+ * Removes an app from the temporary whitelist and notifies the observers.
+ */
+ private void removePowerSaveTempWhitelistAppInternal(String packageName, int userId) {
+ try {
+ final int uid = getContext().getPackageManager().getPackageUidAsUser(
+ packageName, userId);
+ final int appId = UserHandle.getAppId(uid);
+ removePowerSaveTempWhitelistAppDirectInternal(appId);
+ } catch (NameNotFoundException e) {
+ }
+ }
+
+ private void removePowerSaveTempWhitelistAppDirectInternal(int appId) {
+ synchronized (this) {
+ final int idx = mTempWhitelistAppIdEndTimes.indexOfKey(appId);
+ if (idx < 0) {
+ // Nothing else to do
+ return;
+ }
+ final String reason = mTempWhitelistAppIdEndTimes.valueAt(idx).second;
+ mTempWhitelistAppIdEndTimes.removeAt(idx);
+ onAppRemovedFromTempWhitelistLocked(appId, reason);
+ }
+ }
+
private void postTempActiveTimeoutMessage(int uid, long delay) {
if (DEBUG) {
Slog.d(TAG, "postTempActiveTimeoutMessage: uid=" + uid + ", delay=" + delay);
@@ -1842,18 +1888,7 @@
}
if (timeNow >= entry.first.value) {
mTempWhitelistAppIdEndTimes.delete(uid);
- if (DEBUG) {
- Slog.d(TAG, "Removing UID " + uid + " from temp whitelist");
- }
- updateTempWhitelistAppIdsLocked(uid, false);
- mHandler.obtainMessage(MSG_REPORT_TEMP_APP_WHITELIST_CHANGED, uid, 0)
- .sendToTarget();
- reportTempWhitelistChangedLocked();
- try {
- mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_TEMP_WHITELIST_FINISH,
- entry.second, uid);
- } catch (RemoteException e) {
- }
+ onAppRemovedFromTempWhitelistLocked(uid, entry.second);
} else {
// Need more time
if (DEBUG) {
@@ -1864,6 +1899,22 @@
}
}
+ @GuardedBy("this")
+ private void onAppRemovedFromTempWhitelistLocked(int appId, String reason) {
+ if (DEBUG) {
+ Slog.d(TAG, "Removing appId " + appId + " from temp whitelist");
+ }
+ updateTempWhitelistAppIdsLocked(appId, false);
+ mHandler.obtainMessage(MSG_REPORT_TEMP_APP_WHITELIST_CHANGED, appId, 0)
+ .sendToTarget();
+ reportTempWhitelistChangedLocked();
+ try {
+ mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_TEMP_WHITELIST_FINISH,
+ reason, appId);
+ } catch (RemoteException e) {
+ }
+ }
+
public void exitIdleInternal(String reason) {
synchronized (this) {
becomeActiveLocked(reason, Binder.getCallingUid());
@@ -2477,13 +2528,7 @@
}
mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
}
- if (mLocalAlarmManager != null) {
- if (DEBUG) {
- Slog.d(TAG, "Setting alarm whitelist to "
- + Arrays.toString(mPowerSaveWhitelistUserAppIdArray));
- }
- mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray);
- }
+ passWhiteListToForceAppStandbyTrackerLocked();
}
private void updateTempWhitelistAppIdsLocked(int appId, boolean adding) {
@@ -2509,6 +2554,7 @@
}
mLocalPowerManager.setDeviceIdleTempWhitelist(mTempWhitelistAppIdArray);
}
+ passWhiteListToForceAppStandbyTrackerLocked();
}
private void reportPowerSaveWhitelistChangedLocked() {
@@ -2523,6 +2569,12 @@
getContext().sendBroadcastAsUser(intent, UserHandle.SYSTEM);
}
+ private void passWhiteListToForceAppStandbyTrackerLocked() {
+ ForceAppStandbyTracker.getInstance(getContext()).setPowerSaveWhitelistAppIds(
+ mPowerSaveWhitelistAllAppIdArray,
+ mTempWhitelistAppIdArray);
+ }
+
void readConfigFileLocked() {
if (DEBUG) Slog.d(TAG, "Reading config from " + mConfigFile.getBaseFile());
mPowerSaveWhitelistUserApps.clear();
@@ -2700,9 +2752,11 @@
+ "changes made using this won't be persisted across boots");
pw.println(" tempwhitelist");
pw.println(" Print packages that are temporarily whitelisted.");
- pw.println(" tempwhitelist [-u USER] [-d DURATION] [package ..]");
- pw.println(" Temporarily place packages in whitelist for DURATION milliseconds.");
+ pw.println(" tempwhitelist [-u USER] [-d DURATION] [-r] [package]");
+ pw.println(" Temporarily place package in whitelist for DURATION milliseconds.");
pw.println(" If no DURATION is specified, 10 seconds is used");
+ pw.println(" If [-r] option is used, then the package is removed from temp whitelist "
+ + "and any [-d] is ignored");
}
class Shell extends ShellCommand {
@@ -2986,6 +3040,7 @@
}
} else if ("tempwhitelist".equals(cmd)) {
long duration = 10000;
+ boolean removePkg = false;
String opt;
while ((opt=shell.getNextOption()) != null) {
if ("-u".equals(opt)) {
@@ -3002,16 +3057,25 @@
return -1;
}
duration = Long.parseLong(opt);
+ } else if ("-r".equals(opt)) {
+ removePkg = true;
}
}
String arg = shell.getNextArg();
if (arg != null) {
try {
- addPowerSaveTempWhitelistAppChecked(arg, duration, shell.userId, "shell");
+ if (removePkg) {
+ removePowerSaveTempWhitelistAppChecked(arg, shell.userId);
+ } else {
+ addPowerSaveTempWhitelistAppChecked(arg, duration, shell.userId, "shell");
+ }
} catch (Exception e) {
pw.println("Failed: " + e);
return -1;
}
+ } else if (removePkg) {
+ pw.println("[-r] requires a package name");
+ return -1;
} else {
dumpTempWhitelistSchedule(pw, false);
}
diff --git a/services/core/java/com/android/server/DisplayThread.java b/services/core/java/com/android/server/DisplayThread.java
index cad2a61..85c799c 100644
--- a/services/core/java/com/android/server/DisplayThread.java
+++ b/services/core/java/com/android/server/DisplayThread.java
@@ -40,7 +40,7 @@
if (sInstance == null) {
sInstance = new DisplayThread();
sInstance.start();
- sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
sHandler = new Handler(sInstance.getLooper());
}
}
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index d3ce306..6174aec 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -32,9 +32,11 @@
# The device is being asked to go into a soft sleep (typically by the ungaze gesture).
# It logs the time remaining before the device would've normally gone to sleep without the request.
2731 power_soft_sleep_requested (savedwaketimems|2)
+# Power save state has changed. See BatterySaverController.java for the details.
+2739 battery_saver_mode (prevOffOrOn|1|5),(nowOffOrOn|1|5),(interactive|1|5),(features|3|5)
#
-# Leave IDs through 2739 for more power logs (2730 used by battery_discharge above)
+# Leave IDs through 2740 for more power logs (2730 used by battery_discharge above)
#
diff --git a/services/core/java/com/android/server/FgThread.java b/services/core/java/com/android/server/FgThread.java
index 18fb477..021bfaa 100644
--- a/services/core/java/com/android/server/FgThread.java
+++ b/services/core/java/com/android/server/FgThread.java
@@ -39,7 +39,7 @@
if (sInstance == null) {
sInstance = new FgThread();
sInstance.start();
- sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
sHandler = new Handler(sInstance.getLooper());
}
}
diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/ForceAppStandbyTracker.java
index 5dd3ee0..61d3833 100644
--- a/services/core/java/com/android/server/ForceAppStandbyTracker.java
+++ b/services/core/java/com/android/server/ForceAppStandbyTracker.java
@@ -16,13 +16,18 @@
package com.android.server;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.AppOpsManager.PackageOps;
+import android.app.IActivityManager;
import android.app.IUidObserver;
+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.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.RemoteException;
@@ -30,21 +35,36 @@
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Pair;
-import android.util.Slog;
import android.util.SparseBooleanArray;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
+import com.android.server.ForceAppStandbyTrackerProto.RunAnyInBackgroundRestrictedPackages;
+import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.List;
/**
- * Class to track OP_RUN_ANY_IN_BACKGROUND, UID foreground state and "force all app standby".
+ * Class to keep track of the information related to "force app standby", which includes:
+ * - OP_RUN_ANY_IN_BACKGROUND for each package
+ * - UID foreground state
+ * - User+system power save whitelist
+ * - Temporary power save whitelist
+ * - Global "force all apps standby" mode enforced by battery saver.
*
- * TODO Clean up cache when a user is deleted.
- * TODO Add unit tests. b/68769804.
+ * TODO: In general, we can reduce the number of callbacks by checking all signals before sending
+ * each callback. For example, even when an UID comes into the foreground, if it wasn't
+ * originally restricted, then there's no need to send an event.
+ * Doing this would be error-prone, so we punt it for now, but we should revisit it later.
+ *
+ * Test:
+ atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
*/
public class ForceAppStandbyTracker {
private static final String TAG = "ForceAppStandbyTracker";
@@ -55,22 +75,32 @@
private final Object mLock = new Object();
private final Context mContext;
+ @VisibleForTesting
+ static final int TARGET_OP = AppOpsManager.OP_RUN_ANY_IN_BACKGROUND;
+
+ IActivityManager mIActivityManager;
AppOpsManager mAppOpsManager;
IAppOpsService mAppOpsService;
PowerManagerInternal mPowerManagerInternal;
- private final Handler mCallbackHandler;
+ private final MyHandler mHandler;
/**
* Pair of (uid (not user-id), packageName) with OP_RUN_ANY_IN_BACKGROUND *not* allowed.
*/
@GuardedBy("mLock")
- final ArraySet<Pair<Integer, String>> mForcedAppStandbyUidPackages = new ArraySet<>();
+ final ArraySet<Pair<Integer, String>> mRunAnyRestrictedPackages = new ArraySet<>();
@GuardedBy("mLock")
final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
@GuardedBy("mLock")
+ private int[] mPowerWhitelistedAllAppIds = new int[0];
+
+ @GuardedBy("mLock")
+ private int[] mTempWhitelistedAppIds = mPowerWhitelistedAllAppIds;
+
+ @GuardedBy("mLock")
final ArraySet<Listener> mListeners = new ArraySet<>();
@GuardedBy("mLock")
@@ -80,16 +110,116 @@
boolean mForceAllAppsStandby;
public static abstract class Listener {
- public void onRestrictionChanged(int uid, @Nullable String packageName) {
+ /**
+ * This is called when the OP_RUN_ANY_IN_BACKGROUND appops changed for a package.
+ */
+ private void onRunAnyAppOpsChanged(ForceAppStandbyTracker sender,
+ int uid, @NonNull String packageName) {
+ updateJobsForUidPackage(uid, packageName);
+
+ if (!sender.areAlarmsRestricted(uid, packageName)) {
+ unblockAlarmsForUidPackage(uid, packageName);
+ }
}
- public void onGlobalRestrictionChanged() {
+ /**
+ * This is called when the foreground state changed for a UID.
+ */
+ private void onUidForegroundStateChanged(ForceAppStandbyTracker sender, int uid) {
+ updateJobsForUid(uid);
+
+ if (sender.isInForeground(uid)) {
+ unblockAlarmsForUid(uid);
+ }
+ }
+
+ /**
+ * This is called when an app-id(s) is removed from the power save whitelist.
+ */
+ private void onPowerSaveUnwhitelisted(ForceAppStandbyTracker sender) {
+ updateAllJobs();
+ unblockAllUnrestrictedAlarms();
+ }
+
+ /**
+ * This is called when the power save whitelist changes, excluding the
+ * {@link #onPowerSaveUnwhitelisted} case.
+ */
+ private void onPowerSaveWhitelistedChanged(ForceAppStandbyTracker sender) {
+ updateAllJobs();
+ }
+
+ /**
+ * This is called when the temp whitelist changes.
+ */
+ private void onTempPowerSaveWhitelistChanged(ForceAppStandbyTracker sender) {
+
+ // TODO This case happens rather frequently; consider optimizing and update jobs
+ // only for affected app-ids.
+
+ updateAllJobs();
+ }
+
+ /**
+ * This is called when the global "force all apps standby" flag changes.
+ */
+ private void onForceAllAppsStandbyChanged(ForceAppStandbyTracker sender) {
+ updateAllJobs();
+
+ if (!sender.isForceAllAppsStandbyEnabled()) {
+ unblockAllUnrestrictedAlarms();
+ }
+ }
+
+ /**
+ * Called when the job restrictions for multiple UIDs might have changed, so the job
+ * scheduler should re-evaluate all restrictions for all jobs.
+ */
+ public void updateAllJobs() {
+ }
+
+ /**
+ * Called when the job restrictions for a UID might have changed, so the job
+ * scheduler should re-evaluate all restrictions for all jobs.
+ */
+ public void updateJobsForUid(int uid) {
+ }
+
+ /**
+ * Called when the job restrictions for a UID - package might have changed, so the job
+ * scheduler should re-evaluate all restrictions for all jobs.
+ */
+ public void updateJobsForUidPackage(int uid, String packageName) {
+ }
+
+ /**
+ * Called when the job restrictions for multiple UIDs might have changed, so the alarm
+ * manager should re-evaluate all restrictions for all blocked jobs.
+ */
+ public void unblockAllUnrestrictedAlarms() {
+ }
+
+ /**
+ * Called when all jobs for a specific UID are unblocked.
+ */
+ public void unblockAlarmsForUid(int uid) {
+ }
+
+ /**
+ * Called when all alarms for a specific UID - package are unblocked.
+ */
+ public void unblockAlarmsForUidPackage(int uid, String packageName) {
}
}
- private ForceAppStandbyTracker(Context context) {
+ @VisibleForTesting
+ ForceAppStandbyTracker(Context context, Looper looper) {
mContext = context;
- mCallbackHandler = FgThread.getHandler();
+ mHandler = new MyHandler(looper);
+ }
+
+ private ForceAppStandbyTracker(Context context) {
+ this(context, FgThread.get().getLooper());
}
/**
@@ -112,45 +242,65 @@
}
mStarted = true;
- mAppOpsManager = Preconditions.checkNotNull(
- mContext.getSystemService(AppOpsManager.class));
- mAppOpsService = Preconditions.checkNotNull(
- IAppOpsService.Stub.asInterface(
- ServiceManager.getService(Context.APP_OPS_SERVICE)));
- mPowerManagerInternal = Preconditions.checkNotNull(
- LocalServices.getService(PowerManagerInternal.class));
+ mIActivityManager = Preconditions.checkNotNull(injectIActivityManager());
+ mAppOpsManager = Preconditions.checkNotNull(injectAppOpsManager());
+ mAppOpsService = Preconditions.checkNotNull(injectIAppOpsService());
+ mPowerManagerInternal = Preconditions.checkNotNull(injectPowerManagerInternal());
try {
- ActivityManager.getService().registerUidObserver(new UidObserver(),
+ mIActivityManager.registerUidObserver(new UidObserver(),
ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_IDLE
| ActivityManager.UID_OBSERVER_ACTIVE,
ActivityManager.PROCESS_STATE_UNKNOWN, null);
- mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, null,
+ mAppOpsService.startWatchingMode(TARGET_OP, null,
new AppOpsWatcher());
} catch (RemoteException e) {
// shouldn't happen.
}
- mPowerManagerInternal.registerLowPowerModeObserver(
- ServiceType.FORCE_ALL_APPS_STANDBY,
- state -> updateForceAllAppsStandby(state.batterySaverEnabled));
-
- updateForceAllAppsStandby(
- mPowerManagerInternal.getLowPowerState(ServiceType.FORCE_ALL_APPS_STANDBY)
- .batterySaverEnabled);
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_REMOVED);
+ mContext.registerReceiver(new MyReceiver(), filter);
refreshForcedAppStandbyUidPackagesLocked();
+
+ mPowerManagerInternal.registerLowPowerModeObserver(
+ ServiceType.FORCE_ALL_APPS_STANDBY,
+ (state) -> updateForceAllAppsStandby(state.batterySaverEnabled));
+
+ updateForceAllAppsStandby(mPowerManagerInternal.getLowPowerState(
+ ServiceType.FORCE_ALL_APPS_STANDBY).batterySaverEnabled);
}
}
+ @VisibleForTesting
+ AppOpsManager injectAppOpsManager() {
+ return mContext.getSystemService(AppOpsManager.class);
+ }
+
+ @VisibleForTesting
+ IAppOpsService injectIAppOpsService() {
+ return IAppOpsService.Stub.asInterface(
+ ServiceManager.getService(Context.APP_OPS_SERVICE));
+ }
+
+ @VisibleForTesting
+ IActivityManager injectIActivityManager() {
+ return ActivityManager.getService();
+ }
+
+ @VisibleForTesting
+ PowerManagerInternal injectPowerManagerInternal() {
+ return LocalServices.getService(PowerManagerInternal.class);
+ }
+
/**
- * Update {@link #mForcedAppStandbyUidPackages} with the current app ops state.
+ * Update {@link #mRunAnyRestrictedPackages} with the current app ops state.
*/
private void refreshForcedAppStandbyUidPackagesLocked() {
- final int op = AppOpsManager.OP_RUN_ANY_IN_BACKGROUND;
-
- mForcedAppStandbyUidPackages.clear();
- final List<PackageOps> ops = mAppOpsManager.getPackagesForOps(new int[] {op});
+ mRunAnyRestrictedPackages.clear();
+ final List<PackageOps> ops = mAppOpsManager.getPackagesForOps(
+ new int[] {TARGET_OP});
if (ops == null) {
return;
@@ -162,31 +312,38 @@
for (int j = 0; j < entries.size(); j++) {
AppOpsManager.OpEntry ent = entries.get(j);
- if (ent.getOp() != op) {
+ if (ent.getOp() != TARGET_OP) {
continue;
}
if (ent.getMode() != AppOpsManager.MODE_ALLOWED) {
- mForcedAppStandbyUidPackages.add(Pair.create(
+ mRunAnyRestrictedPackages.add(Pair.create(
pkg.getUid(), pkg.getPackageName()));
}
}
}
}
- boolean isRunAnyInBackgroundAppOpRestricted(int uid, @NonNull String packageName) {
- try {
- return mAppOpsService.checkOperation(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
- uid, packageName) != AppOpsManager.MODE_ALLOWED;
- } catch (RemoteException e) {
- return false; // shouldn't happen.
+ /**
+ * Update {@link #mForceAllAppsStandby} and notifies the listeners.
+ */
+ void updateForceAllAppsStandby(boolean enable) {
+ synchronized (mLock) {
+ if (enable == mForceAllAppsStandby) {
+ return;
+ }
+ mForceAllAppsStandby = enable;
+
+ mHandler.notifyForceAllAppsStandbyChanged();
}
}
private int findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName) {
- // TODO Maybe we should switch to indexOf(Pair.create()) if the array size is too big.
- final int size = mForcedAppStandbyUidPackages.size();
+ final int size = mRunAnyRestrictedPackages.size();
+ if (size > 8) {
+ return mRunAnyRestrictedPackages.indexOf(Pair.create(uid, packageName));
+ }
for (int i = 0; i < size; i++) {
- final Pair<Integer, String> pair = mForcedAppStandbyUidPackages.valueAt(i);
+ final Pair<Integer, String> pair = mRunAnyRestrictedPackages.valueAt(i);
if ((pair.first == uid) && packageName.equals(pair.second)) {
return i;
@@ -196,13 +353,16 @@
}
/**
- * @return whether a uid package-name pair is in mForcedAppStandbyUidPackages.
+ * @return whether a uid package-name pair is in mRunAnyRestrictedPackages.
*/
- boolean isUidPackageRestrictedLocked(int uid, @NonNull String packageName) {
+ boolean isRunAnyRestrictedLocked(int uid, @NonNull String packageName) {
return findForcedAppStandbyUidPackageIndexLocked(uid, packageName) >= 0;
}
- boolean updateRestrictedUidPackageLocked(int uid, @NonNull String packageName,
+ /**
+ * Add to / remove from {@link #mRunAnyRestrictedPackages}.
+ */
+ boolean updateForcedAppStandbyUidPackageLocked(int uid, @NonNull String packageName,
boolean restricted) {
final int index = findForcedAppStandbyUidPackageIndexLocked(uid, packageName);
final boolean wasRestricted = index >= 0;
@@ -210,13 +370,16 @@
return false;
}
if (restricted) {
- mForcedAppStandbyUidPackages.add(Pair.create(uid, packageName));
+ mRunAnyRestrictedPackages.add(Pair.create(uid, packageName));
} else {
- mForcedAppStandbyUidPackages.removeAt(index);
+ mRunAnyRestrictedPackages.removeAt(index);
}
return true;
}
+ /**
+ * Puts a UID to {@link #mForegroundUids}.
+ */
void uidToForeground(int uid) {
synchronized (mLock) {
if (!UserHandle.isApp(uid)) {
@@ -228,10 +391,13 @@
return;
}
mForegroundUids.put(uid, true);
- notifyForUidPackage(uid, null);
+ mHandler.notifyUidForegroundStateChanged(uid);
}
}
+ /**
+ * Sets false for a UID {@link #mForegroundUids}, or remove it when {@code remove} is true.
+ */
void uidToBackground(int uid, boolean remove) {
synchronized (mLock) {
if (!UserHandle.isApp(uid)) {
@@ -247,13 +413,11 @@
} else {
mForegroundUids.put(uid, false);
}
- notifyForUidPackage(uid, null);
+ mHandler.notifyUidForegroundStateChanged(uid);
}
}
- // Event handlers
-
- final class UidObserver extends IUidObserver.Stub {
+ private final class UidObserver extends IUidObserver.Stub {
@Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
}
@@ -277,11 +441,28 @@
private final class AppOpsWatcher extends IAppOpsCallback.Stub {
@Override
public void opChanged(int op, int uid, String packageName) throws RemoteException {
+ boolean restricted = false;
+ try {
+ restricted = mAppOpsService.checkOperation(TARGET_OP,
+ uid, packageName) != AppOpsManager.MODE_ALLOWED;
+ } catch (RemoteException e) {
+ // Shouldn't happen
+ }
synchronized (mLock) {
- final boolean restricted = isRunAnyInBackgroundAppOpRestricted(uid, packageName);
+ if (updateForcedAppStandbyUidPackageLocked(uid, packageName, restricted)) {
+ mHandler.notifyRunAnyAppOpsChanged(uid, packageName);
+ }
+ }
+ }
+ }
- if (updateRestrictedUidPackageLocked(uid, packageName, restricted)) {
- notifyForUidPackage(uid, packageName);
+ private final class MyReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ if (userId > 0) {
+ mHandler.doUserRemoved(userId);
}
}
}
@@ -293,31 +474,183 @@
}
}
- void notifyForUidPackage(int uid, String packageName) {
- mCallbackHandler.post(() -> {
- for (Listener l : cloneListeners()) {
- l.onRestrictionChanged(uid, packageName);
- }
- });
- }
+ private class MyHandler extends Handler {
+ private static final int MSG_UID_STATE_CHANGED = 1;
+ private static final int MSG_RUN_ANY_CHANGED = 2;
+ private static final int MSG_ALL_UNWHITELISTED = 3;
+ private static final int MSG_ALL_WHITELIST_CHANGED = 4;
+ private static final int MSG_TEMP_WHITELIST_CHANGED = 5;
+ private static final int MSG_FORCE_ALL_CHANGED = 6;
- void notifyGlobal() {
- mCallbackHandler.post(() -> {
- for (Listener l : cloneListeners()) {
- l.onGlobalRestrictionChanged();
- }
- });
- }
+ private static final int MSG_USER_REMOVED = 7;
- void updateForceAllAppsStandby(boolean forceAllAppsStandby) {
- synchronized (mLock) {
- if (mForceAllAppsStandby == forceAllAppsStandby) {
- return;
- }
- mForceAllAppsStandby = forceAllAppsStandby;
- Slog.i(TAG, "Force all app standby: " + mForceAllAppsStandby);
- notifyGlobal();
+ public MyHandler(Looper looper) {
+ super(looper);
}
+
+ public void notifyUidForegroundStateChanged(int uid) {
+ obtainMessage(MSG_UID_STATE_CHANGED, uid, 0).sendToTarget();
+ }
+ public void notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName) {
+ obtainMessage(MSG_RUN_ANY_CHANGED, uid, 0, packageName).sendToTarget();
+ }
+
+ public void notifyAllUnwhitelisted() {
+ obtainMessage(MSG_ALL_UNWHITELISTED).sendToTarget();
+ }
+
+ public void notifyAllWhitelistChanged() {
+ obtainMessage(MSG_ALL_WHITELIST_CHANGED).sendToTarget();
+ }
+
+ public void notifyTempWhitelistChanged() {
+ obtainMessage(MSG_TEMP_WHITELIST_CHANGED).sendToTarget();
+ }
+
+ public void notifyForceAllAppsStandbyChanged() {
+ obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
+ }
+
+ public void doUserRemoved(int userId) {
+ obtainMessage(MSG_USER_REMOVED, userId, 0).sendToTarget();
+ }
+
+ @Override
+ public void dispatchMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_USER_REMOVED:
+ handleUserRemoved(msg.arg1);
+ return;
+ }
+
+ // Only notify the listeners when started.
+ synchronized (mLock) {
+ if (!mStarted) {
+ return;
+ }
+ }
+ final ForceAppStandbyTracker sender = ForceAppStandbyTracker.this;
+
+ switch (msg.what) {
+ case MSG_UID_STATE_CHANGED:
+ for (Listener l : cloneListeners()) {
+ l.onUidForegroundStateChanged(sender, msg.arg1);
+ }
+ return;
+ case MSG_RUN_ANY_CHANGED:
+ for (Listener l : cloneListeners()) {
+ l.onRunAnyAppOpsChanged(sender, msg.arg1, (String) msg.obj);
+ }
+ return;
+ case MSG_ALL_UNWHITELISTED:
+ for (Listener l : cloneListeners()) {
+ l.onPowerSaveUnwhitelisted(sender);
+ }
+ return;
+ case MSG_ALL_WHITELIST_CHANGED:
+ for (Listener l : cloneListeners()) {
+ l.onPowerSaveWhitelistedChanged(sender);
+ }
+ return;
+ case MSG_TEMP_WHITELIST_CHANGED:
+ for (Listener l : cloneListeners()) {
+ l.onTempPowerSaveWhitelistChanged(sender);
+ }
+ return;
+ case MSG_FORCE_ALL_CHANGED:
+ for (Listener l : cloneListeners()) {
+ l.onForceAllAppsStandbyChanged(sender);
+ }
+ return;
+ case MSG_USER_REMOVED:
+ handleUserRemoved(msg.arg1);
+ return;
+ }
+ }
+ }
+
+ void handleUserRemoved(int removedUserId) {
+ synchronized (mLock) {
+ for (int i = mRunAnyRestrictedPackages.size() - 1; i >= 0; i--) {
+ final Pair<Integer, String> pair = mRunAnyRestrictedPackages.valueAt(i);
+ final int uid = pair.first;
+ final int userId = UserHandle.getUserId(uid);
+
+ if (userId == removedUserId) {
+ mRunAnyRestrictedPackages.removeAt(i);
+ }
+ }
+ for (int i = mForegroundUids.size() - 1; i >= 0; i--) {
+ final int uid = mForegroundUids.keyAt(i);
+ final int userId = UserHandle.getUserId(uid);
+
+ if (userId == removedUserId) {
+ mForegroundUids.removeAt(i);
+ }
+ }
+ }
+ }
+
+ /**
+ * Called by device idle controller to update the power save whitelists.
+ */
+ public void setPowerSaveWhitelistAppIds(
+ int[] powerSaveWhitelistAllAppIdArray, int[] tempWhitelistAppIdArray) {
+ synchronized (mLock) {
+ final int[] previousWhitelist = mPowerWhitelistedAllAppIds;
+ final int[] previousTempWhitelist = mTempWhitelistedAppIds;
+
+ mPowerWhitelistedAllAppIds = powerSaveWhitelistAllAppIdArray;
+ mTempWhitelistedAppIds = tempWhitelistAppIdArray;
+
+ if (isAnyAppIdUnwhitelisted(previousWhitelist, mPowerWhitelistedAllAppIds)) {
+ mHandler.notifyAllUnwhitelisted();
+ } else if (!Arrays.equals(previousWhitelist, mPowerWhitelistedAllAppIds)) {
+ mHandler.notifyAllWhitelistChanged();
+ }
+
+ if (!Arrays.equals(previousTempWhitelist, mTempWhitelistedAppIds)) {
+ mHandler.notifyTempWhitelistChanged();
+ }
+
+ }
+ }
+
+ /**
+ * @retunr true if a sorted app-id array {@code prevArray} has at least one element
+ * that's not in a sorted app-id array {@code newArray}.
+ */
+ @VisibleForTesting
+ static boolean isAnyAppIdUnwhitelisted(int[] prevArray, int[] newArray) {
+ int i1 = 0;
+ int i2 = 0;
+ boolean prevFinished;
+ boolean newFinished;
+
+ for (;;) {
+ prevFinished = i1 >= prevArray.length;
+ newFinished = i2 >= newArray.length;
+ if (prevFinished || newFinished) {
+ break;
+ }
+ int a1 = prevArray[i1];
+ int a2 = newArray[i2];
+
+ if (a1 == a2) {
+ i1++;
+ i2++;
+ continue;
+ }
+ if (a1 < a2) {
+ // prevArray has an element that's not in a2.
+ return true;
+ }
+ i2++;
+ }
+ if (prevFinished) {
+ return false;
+ }
+ return newFinished;
}
// Public interface.
@@ -332,21 +665,51 @@
}
/**
- * Whether force-app-standby is effective for a UID package-name.
+ * @return whether alarms should be restricted for a UID package-name.
*/
- public boolean isRestricted(int uid, @NonNull String packageName) {
+ public boolean areAlarmsRestricted(int uid, @NonNull String packageName) {
+ return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ false);
+ }
+
+ /**
+ * @return whether jobs should be restricted for a UID package-name.
+ */
+ public boolean areJobsRestricted(int uid, @NonNull String packageName) {
+ return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ true);
+ }
+
+ /**
+ * @return whether force-app-standby is effective for a UID package-name.
+ */
+ private boolean isRestricted(int uid, @NonNull String packageName,
+ boolean useTempWhitelistToo) {
if (isInForeground(uid)) {
return false;
}
synchronized (mLock) {
+ // Whitelisted?
+ final int appId = UserHandle.getAppId(uid);
+ if (ArrayUtils.contains(mPowerWhitelistedAllAppIds, appId)) {
+ return false;
+ }
+ if (useTempWhitelistToo &&
+ ArrayUtils.contains(mTempWhitelistedAppIds, appId)) {
+ return false;
+ }
+
if (mForceAllAppsStandby) {
return true;
}
- return isUidPackageRestrictedLocked(uid, packageName);
+
+ return isRunAnyRestrictedLocked(uid, packageName);
}
}
- /** For dumpsys -- otherwise the callers don't need to know it. */
+ /**
+ * @return whether a UID is in the foreground or not.
+ *
+ * Note clients normally shouldn't need to access it. It's only for dumpsys.
+ */
public boolean isInForeground(int uid) {
if (!UserHandle.isApp(uid)) {
return true;
@@ -356,31 +719,120 @@
}
}
- /** For dumpsys -- otherwise the callers don't need to know it. */
- public boolean isForceAllAppsStandbyEnabled() {
+ /**
+ * @return whether force all apps standby is enabled or not.
+ *
+ * Note clients normally shouldn't need to access it.
+ */
+ boolean isForceAllAppsStandbyEnabled() {
synchronized (mLock) {
return mForceAllAppsStandby;
}
}
- /** For dumpsys -- otherwise the callers don't need to know it. */
+ /**
+ * @return whether a UID/package has {@code OP_RUN_ANY_IN_BACKGROUND} allowed or not.
+ *
+ * Note clients normally shouldn't need to access it. It's only for dumpsys.
+ */
public boolean isRunAnyInBackgroundAppOpsAllowed(int uid, @NonNull String packageName) {
synchronized (mLock) {
- return !isUidPackageRestrictedLocked(uid, packageName);
+ return !isRunAnyRestrictedLocked(uid, packageName);
}
}
- /** For dumpsys -- otherwise the callers don't need to know it. */
- public SparseBooleanArray getForegroudUids() {
+ /**
+ * @return whether a UID is in the user / system defined power-save whitelist or not.
+ *
+ * Note clients normally shouldn't need to access it. It's only for dumpsys.
+ */
+ public boolean isUidPowerSaveWhitelisted(int uid) {
synchronized (mLock) {
- return mForegroundUids.clone();
+ return ArrayUtils.contains(mPowerWhitelistedAllAppIds, UserHandle.getAppId(uid));
}
}
- /** For dumpsys -- otherwise the callers don't need to know it. */
- public ArraySet<Pair<Integer, String>> getRestrictedUidPackages() {
+ /**
+ * @return whether a UID is in the temp power-save whitelist or not.
+ *
+ * Note clients normally shouldn't need to access it. It's only for dumpsys.
+ */
+ public boolean isUidTempPowerSaveWhitelisted(int uid) {
synchronized (mLock) {
- return new ArraySet(mForcedAppStandbyUidPackages);
+ return ArrayUtils.contains(mTempWhitelistedAppIds, UserHandle.getAppId(uid));
+ }
+ }
+
+ public void dump(PrintWriter pw, String indent) {
+ synchronized (mLock) {
+ pw.print(indent);
+ pw.print("Force all apps standby: ");
+ pw.println(isForceAllAppsStandbyEnabled());
+
+ pw.print(indent);
+ pw.print("Foreground uids: [");
+
+ String sep = "";
+ for (int i = 0; i < mForegroundUids.size(); i++) {
+ if (mForegroundUids.valueAt(i)) {
+ pw.print(sep);
+ pw.print(UserHandle.formatUid(mForegroundUids.keyAt(i)));
+ sep = " ";
+ }
+ }
+ pw.println("]");
+
+ pw.print(indent);
+ pw.print("Whitelist appids: ");
+ pw.println(Arrays.toString(mPowerWhitelistedAllAppIds));
+
+ pw.print(indent);
+ pw.print("Temp whitelist appids: ");
+ pw.println(Arrays.toString(mTempWhitelistedAppIds));
+
+ pw.print(indent);
+ pw.println("Restricted packages:");
+ for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
+ pw.print(indent);
+ pw.print(" ");
+ pw.print(UserHandle.formatUid(uidAndPackage.first));
+ pw.print(" ");
+ pw.print(uidAndPackage.second);
+ pw.println();
+ }
+ }
+ }
+
+ public void dumpProto(ProtoOutputStream proto, long fieldId) {
+ synchronized (mLock) {
+ final long token = proto.start(fieldId);
+
+ proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY, mForceAllAppsStandby);
+
+ for (int i = 0; i < mForegroundUids.size(); i++) {
+ if (mForegroundUids.valueAt(i)) {
+ proto.write(ForceAppStandbyTrackerProto.FOREGROUND_UIDS,
+ mForegroundUids.keyAt(i));
+ }
+ }
+
+ for (int appId : mPowerWhitelistedAllAppIds) {
+ proto.write(ForceAppStandbyTrackerProto.POWER_SAVE_WHITELIST_APP_IDS, appId);
+ }
+
+ for (int appId : mTempWhitelistedAppIds) {
+ proto.write(ForceAppStandbyTrackerProto.TEMP_POWER_SAVE_WHITELIST_APP_IDS, appId);
+ }
+
+ for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
+ final long token2 = proto.start(
+ ForceAppStandbyTrackerProto.RUN_ANY_IN_BACKGROUND_RESTRICTED_PACKAGES);
+ proto.write(RunAnyInBackgroundRestrictedPackages.UID, uidAndPackage.first);
+ proto.write(RunAnyInBackgroundRestrictedPackages.PACKAGE_NAME,
+ uidAndPackage.second);
+ proto.end(token2);
+ }
+ proto.end(token);
}
}
}
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index fc57a0d..dc35051 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -108,6 +108,8 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.service.vr.IVrManager;
+import android.service.vr.IVrStateCallbacks;
import android.text.TextUtils;
import android.text.style.SuggestionSpan;
import android.util.ArrayMap;
@@ -189,6 +191,7 @@
static final int MSG_CREATE_SESSION = 1050;
static final int MSG_START_INPUT = 2000;
+ static final int MSG_START_VR_INPUT = 2010;
static final int MSG_UNBIND_CLIENT = 3000;
static final int MSG_BIND_CLIENT = 3010;
@@ -317,6 +320,28 @@
}
}
+ /**
+ * VR state callback.
+ * Listens for when VR mode finishes.
+ */
+ private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
+ @Override
+ public void onVrStateChanged(boolean enabled) {
+ if (!enabled) {
+ restoreNonVrImeFromSettingsNoCheck();
+ }
+ }
+ };
+
+ private void restoreNonVrImeFromSettingsNoCheck() {
+ // switch back to non-VR InputMethod from settings.
+ synchronized (mMethodMap) {
+ final String lastInputId = mSettings.getSelectedInputMethod();
+ setInputMethodLocked(lastInputId,
+ mSettings.getSelectedInputMethodSubtypeId(lastInputId));
+ }
+ }
+
static final class ClientState {
final IInputMethodClient client;
final IInputContext inputContext;
@@ -863,6 +888,30 @@
}
/**
+ * Start a VR InputMethod that matches IME with package name of {@param component}.
+ * Note: This method is called from {@link VrManager}.
+ */
+ private void startVrInputMethodNoCheck(@Nullable ComponentName component) {
+ if (component == null) {
+ // clear the current VR-only IME (if any) and restore normal IME.
+ restoreNonVrImeFromSettingsNoCheck();
+ return;
+ }
+
+ synchronized (mMethodMap) {
+ String packageName = component.getPackageName();
+ for (InputMethodInfo info : mMethodList) {
+ if (TextUtils.equals(info.getPackageName(), packageName) && info.isVrOnly()) {
+ // set this is as current inputMethod without updating settings.
+ setInputMethodEnabled(info.getId(), true);
+ setInputMethodLocked(info.getId(), NOT_A_SUBTYPE_ID);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
* Handles {@link Intent#ACTION_LOCALE_CHANGED}.
*
* <p>Note: For historical reasons, {@link Intent#ACTION_LOCALE_CHANGED} has been sent to all
@@ -1338,6 +1387,15 @@
mFileManager = new InputMethodFileManager(mMethodMap, userId);
mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
mSettings, context);
+ // Register VR-state listener.
+ IVrManager vrManager = (IVrManager) ServiceManager.getService(Context.VR_SERVICE);
+ if (vrManager != null) {
+ try {
+ vrManager.registerListener(mVrStateCallbacks);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register VR mode state listener.");
+ }
+ }
}
private void resetDefaultImeLocked(Context context) {
@@ -1562,12 +1620,27 @@
@Override
public List<InputMethodInfo> getInputMethodList() {
+ return getInputMethodList(false /* isVrOnly */);
+ }
+
+ public List<InputMethodInfo> getVrInputMethodList() {
+ return getInputMethodList(true /* isVrOnly */);
+ }
+
+ private List<InputMethodInfo> getInputMethodList(final boolean isVrOnly) {
// TODO: Make this work even for non-current users?
if (!calledFromValidUser()) {
return Collections.emptyList();
}
synchronized (mMethodMap) {
- return new ArrayList<>(mMethodList);
+ ArrayList<InputMethodInfo> methodList = new ArrayList<>();
+ for (InputMethodInfo info : mMethodList) {
+
+ if (info.isVrOnly() == isVrOnly) {
+ methodList.add(info);
+ }
+ }
+ return methodList;
}
}
@@ -3356,6 +3429,9 @@
case MSG_SET_INTERACTIVE:
handleSetInteractive(msg.arg1 != 0);
return true;
+ case MSG_START_VR_INPUT:
+ startVrInputMethodNoCheck((ComponentName) msg.obj);
+ return true;
case MSG_SWITCH_IME:
handleSwitchInputMethod(msg.arg1 != 0);
return true;
@@ -3876,8 +3952,12 @@
private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId,
boolean setSubtypeOnly) {
- // Update the history of InputMethod and Subtype
- mSettings.saveCurrentInputMethodAndSubtypeToHistory(mCurMethodId, mCurrentSubtype);
+ // Updates to InputMethod are transient in VR mode. Its not included in history.
+ final boolean isVrInput = imi != null && imi.isVrOnly();
+ if (!isVrInput) {
+ // Update the history of InputMethod and Subtype
+ mSettings.saveCurrentInputMethodAndSubtypeToHistory(mCurMethodId, mCurrentSubtype);
+ }
mCurUserActionNotificationSequenceNumber =
Math.max(mCurUserActionNotificationSequenceNumber + 1, 1);
@@ -3892,6 +3972,11 @@
mCurUserActionNotificationSequenceNumber, mCurClient));
}
+ if (isVrInput) {
+ // Updates to InputMethod are transient in VR mode. Any changes to Settings are skipped.
+ return;
+ }
+
// Set Subtype here
if (imi == null || subtypeId < 0) {
mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
@@ -4351,6 +4436,11 @@
mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD);
mHandler.sendEmptyMessage(MSG_HIDE_CURRENT_INPUT_METHOD);
}
+
+ @Override
+ public void startVrInputMethodNoCheck(@Nullable ComponentName componentName) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_START_VR_INPUT, componentName));
+ }
}
private static String imeWindowStatusToString(final int imeWindowVis) {
diff --git a/services/core/java/com/android/server/IoThread.java b/services/core/java/com/android/server/IoThread.java
index ad4c194..bfe825a 100644
--- a/services/core/java/com/android/server/IoThread.java
+++ b/services/core/java/com/android/server/IoThread.java
@@ -36,7 +36,7 @@
if (sInstance == null) {
sInstance = new IoThread();
sInstance.start();
- sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
sHandler = new Handler(sInstance.getLooper());
}
}
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index 1ad1404..2c24798 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -69,13 +69,10 @@
private static final String ACTION_POLL =
"com.android.server.NetworkTimeUpdateService.action.POLL";
- private static final int NETWORK_CHANGE_EVENT_DELAY_MS = 1000;
- private static int POLL_REQUEST = 0;
+ private static final int POLL_REQUEST = 0;
private static final long NOT_SET = -1;
private long mNitzTimeSetTime = NOT_SET;
- // TODO: Have a way to look up the timezone we are in
- private long mNitzZoneSetTime = NOT_SET;
private Network mDefaultNetwork = null;
private Context mContext;
@@ -144,7 +141,6 @@
private void registerForTelephonyIntents() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME);
- intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
mContext.registerReceiver(mNitzReceiver, intentFilter);
}
@@ -257,8 +253,6 @@
if (DBG) Log.d(TAG, "Received " + action);
if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {
mNitzTimeSetTime = SystemClock.elapsedRealtime();
- } else if (TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE.equals(action)) {
- mNitzZoneSetTime = SystemClock.elapsedRealtime();
}
}
};
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index f20ca43..f4238f2 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -282,6 +282,7 @@
mBoundUserId = UserHandle.USER_NULL;
if (component != null) {
if (D) Log.d(mTag, "unbinding " + component);
+ mBoundService = null;
mContext.unbindService(this);
}
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 3c955eb..7f0b508 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2192,6 +2192,11 @@
mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
"no permission to access the crypt keeper");
+ if (StorageManager.isFileEncryptedNativeOnly()) {
+ // Not supported on FBE devices
+ return -1;
+ }
+
if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
password = "";
} else if (TextUtils.isEmpty(password)) {
@@ -2268,6 +2273,11 @@
mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
"no permission to access the crypt keeper");
+ if (StorageManager.isFileEncryptedNativeOnly()) {
+ // Not supported on FBE devices
+ return;
+ }
+
try {
mVold.fdeSetField(field, contents);
return;
@@ -2287,6 +2297,11 @@
mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
"no permission to access the crypt keeper");
+ if (StorageManager.isFileEncryptedNativeOnly()) {
+ // Not supported on FBE devices
+ return null;
+ }
+
try {
return mVold.fdeGetField(field);
} catch (Exception e) {
@@ -2568,7 +2583,7 @@
}
@Override
- public int mkdirs(String callingPkg, String appPath) {
+ public void mkdirs(String callingPkg, String appPath) {
final int userId = UserHandle.getUserId(Binder.getCallingUid());
final UserEnvironment userEnv = new UserEnvironment(userId);
@@ -2581,8 +2596,7 @@
try {
appFile = new File(appPath).getCanonicalFile();
} catch (IOException e) {
- Slog.e(TAG, "Failed to resolve " + appPath + ": " + e);
- return -1;
+ throw new IllegalStateException("Failed to resolve " + appPath + ": " + e);
}
// Try translating the app path into a vold path, but require that it
@@ -2597,9 +2611,9 @@
try {
mVold.mkdirs(appPath);
- return 0;
+ return;
} catch (Exception e) {
- Slog.wtf(TAG, e);
+ throw new IllegalStateException("Failed to prepare " + appPath + ": " + e);
}
}
diff --git a/services/core/java/com/android/server/UiThread.java b/services/core/java/com/android/server/UiThread.java
index fd88d26..f813074 100644
--- a/services/core/java/com/android/server/UiThread.java
+++ b/services/core/java/com/android/server/UiThread.java
@@ -47,7 +47,7 @@
sInstance = new UiThread();
sInstance.start();
final Looper looper = sInstance.getLooper();
- looper.setTraceTag(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
looper.setSlowDispatchThresholdMs(SLOW_DISPATCH_THRESHOLD_MS);
sHandler = new Handler(sInstance.getLooper());
}
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 3dbee42..9bfdd0c 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -65,6 +65,12 @@
static final int POSITION_TOP = Integer.MAX_VALUE;
static final int POSITION_BOTTOM = Integer.MIN_VALUE;
+
+ /**
+ * Counter for next free stack ID to use for dynamic activity stacks. Unique across displays.
+ */
+ private static int sNextFreeStackId = 0;
+
private ActivityStackSupervisor mSupervisor;
/** Actual Display this object tracks. */
int mDisplayId;
@@ -231,6 +237,10 @@
return getOrCreateStack(windowingMode, activityType, onTop);
}
+ private int getNextStackId() {
+ return sNextFreeStackId++;
+ }
+
/**
* Creates a stack matching the input windowing mode and activity type on this display.
* @param windowingMode The windowing mode the stack should be created in. If
@@ -278,7 +288,7 @@
}
}
- final int stackId = mSupervisor.getNextStackId();
+ final int stackId = getNextStackId();
return createStackUnchecked(windowingMode, activityType, stackId, onTop);
}
@@ -399,6 +409,16 @@
otherStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
}
} finally {
+ if (mHomeStack != null && !isTopStack(mHomeStack)) {
+ // Whenever split-screen is dismissed we want the home stack directly behind the
+ // currently top stack so it shows up when the top stack is finished.
+ final ActivityStack topStack = getTopStack();
+ // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however
+ // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch
+ // once we have that.
+ mHomeStack.moveToFront("onSplitScreenModeDismissed");
+ topStack.moveToFront("onSplitScreenModeDismissed");
+ }
mSupervisor.mWindowManager.continueSurfaceLayout();
}
}
@@ -413,7 +433,9 @@
|| !otherStack.affectedBySplitScreenResize()) {
continue;
}
- otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
+ false /* animate */, false /* showRecents */,
+ false /* sendNonResizeableNotification */);
}
} finally {
mSupervisor.mWindowManager.continueSurfaceLayout();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 083d306..5d6cf74 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -44,7 +44,9 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
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_LEANBACK_ONLY;
@@ -246,7 +248,9 @@
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.backup.IBackupManager;
+import android.app.servertransaction.ConfigurationChangeItem;
import android.app.usage.UsageEvents;
+import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
import android.content.ActivityNotFoundException;
@@ -317,6 +321,7 @@
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.RemoteCallbackList;
@@ -412,9 +417,11 @@
import com.android.server.ThreadPriorityBooster;
import com.android.server.Watchdog;
import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.am.EventLogTags;
import com.android.server.am.proto.ActivityManagerServiceProto;
import com.android.server.am.proto.BroadcastProto;
import com.android.server.am.proto.GrantUriProto;
+import com.android.server.am.proto.MemInfoProto;
import com.android.server.am.proto.NeededUriGrantsProto;
import com.android.server.am.proto.StickyBroadcastProto;
import com.android.server.firewall.IntentFirewall;
@@ -629,7 +636,9 @@
final ActivityStackSupervisor mStackSupervisor;
private final KeyguardController mKeyguardController;
- final ActivityStarter mActivityStarter;
+ private final ActivityStartController mActivityStartController;
+
+ final ClientLifecycleManager mLifecycleManager;
final TaskChangeNotificationController mTaskChangeNotificationController;
@@ -713,6 +722,12 @@
final UserController mUserController;
+ /**
+ * Packages that are being allowed to perform unrestricted app switches. Mapping is
+ * User -> Type -> uid.
+ */
+ final SparseArray<ArrayMap<String, Integer>> mAllowAppSwitchUids = new SparseArray<>();
+
final AppErrors mAppErrors;
final AppWarnings mAppWarnings;
@@ -1350,7 +1365,7 @@
@GuardedBy("this") boolean mCallFinishBooting = false;
@GuardedBy("this") boolean mBootAnimationComplete = false;
@GuardedBy("this") boolean mLaunchWarningShown = false;
- @GuardedBy("this") boolean mCheckedForSetup = false;
+ private @GuardedBy("this") boolean mCheckedForSetup = false;
final Context mContext;
@@ -1696,7 +1711,6 @@
static final int SHOW_UID_ERROR_UI_MSG = 14;
static final int SHOW_FINGERPRINT_ERROR_UI_MSG = 15;
static final int PROC_START_TIMEOUT_MSG = 20;
- static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
static final int KILL_APPLICATION_MSG = 22;
static final int FINALIZE_PENDING_INTENT_MSG = 23;
static final int POST_HEAVY_NOTIFICATION_MSG = 24;
@@ -1772,6 +1786,11 @@
final boolean mPermissionReviewRequired;
+ /**
+ * Whether to force background check on all apps (for battery saver) or not.
+ */
+ boolean mForceBackgroundCheck;
+
private static String sTheRealBuildSerial = Build.UNKNOWN;
/**
@@ -2061,11 +2080,6 @@
processContentProviderPublishTimedOutLocked(app);
}
} break;
- case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
- synchronized (ActivityManagerService.this) {
- mActivityStarter.doPendingActivityLaunchesLocked(true);
- }
- } break;
case KILL_APPLICATION_MSG: {
synchronized (ActivityManagerService.this) {
final int appId = msg.arg1;
@@ -2554,14 +2568,13 @@
@Override
public void dumpHigh(FileDescriptor fd, PrintWriter pw, String[] args,
boolean asProto) {
- if (asProto) return;
- mActivityManagerService.dumpApplicationMemoryUsage(fd,
- pw, " ", new String[] {"-a"}, false, null);
+ dump(fd, pw, new String[] {"-a"}, asProto);
}
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
- if (asProto) return;
- mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false, null);
+ mActivityManagerService.dumpApplicationMemoryUsage(
+ fd, pw, " ", args, false, null, asProto);
}
};
@@ -2662,7 +2675,7 @@
mContext = mInjector.getContext();
mUiContext = null;
GL_ES_VERSION = 0;
- mActivityStarter = null;
+ mActivityStartController = null;
mAppErrors = null;
mAppWarnings = null;
mAppOpsService = mInjector.getAppOpsService(null, null);
@@ -2687,6 +2700,7 @@
mUserController = null;
mVrController = null;
mLockTaskController = null;
+ mLifecycleManager = null;
}
// Note: This method is invoked on the main thread but may need to attach various
@@ -2785,10 +2799,11 @@
mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
mTaskChangeNotificationController =
new TaskChangeNotificationController(this, mStackSupervisor, mHandler);
- mActivityStarter = new ActivityStarter(this);
+ mActivityStartController = new ActivityStartController(this);
mRecentTasks = createRecentTasks();
mStackSupervisor.setRecentTasks(mRecentTasks);
mLockTaskController = new LockTaskController(mContext, mStackSupervisor, mHandler);
+ mLifecycleManager = new ClientLifecycleManager();
mProcessCpuThread = new Thread("CpuTracker") {
@Override
@@ -2872,6 +2887,7 @@
void onUserStoppedLocked(int userId) {
mRecentTasks.unloadUserDataFromMemoryLocked(userId);
+ mAllowAppSwitchUids.remove(userId);
}
public void initPowerManagement() {
@@ -4103,7 +4119,7 @@
// For ANR debugging to verify if the user activity is the one that actually
// launched.
final String myReason = reason + ":" + userId + ":" + resolvedUserId;
- mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);
+ mActivityStartController.startHomeActivity(intent, aInfo, myReason);
}
} else {
Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
@@ -4136,49 +4152,12 @@
return ai;
}
- /**
- * Starts the "new version setup screen" if appropriate.
- */
- void startSetupActivityLocked() {
- // Only do this once per boot.
- if (mCheckedForSetup) {
- return;
- }
+ boolean getCheckedForSetup() {
+ return mCheckedForSetup;
+ }
- // We will show this screen if the current one is a different
- // version than the last one shown, and we are not running in
- // low-level factory test mode.
- final ContentResolver resolver = mContext.getContentResolver();
- if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL &&
- Settings.Global.getInt(resolver,
- Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
- mCheckedForSetup = true;
-
- // See if we should be showing the platform update setup UI.
- final Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
- final List<ResolveInfo> ris = mContext.getPackageManager().queryIntentActivities(intent,
- PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_META_DATA);
- if (!ris.isEmpty()) {
- final ResolveInfo ri = ris.get(0);
- String vers = ri.activityInfo.metaData != null
- ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
- : null;
- if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
- vers = ri.activityInfo.applicationInfo.metaData.getString(
- Intent.METADATA_SETUP_VERSION);
- }
- String lastVers = Settings.Secure.getString(
- resolver, Settings.Secure.LAST_SETUP_SHOWN);
- if (vers != null && !vers.equals(lastVers)) {
- intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
- intent.setComponent(new ComponentName(
- ri.activityInfo.packageName, ri.activityInfo.name));
- mActivityStarter.startActivityLocked(null, intent, null /*ephemeralIntent*/,
- null, ri.activityInfo, null /*rInfo*/, null, null, null, null, 0, 0, 0,
- null, 0, 0, 0, null, false, false, null, null, "startSetupActivity");
- }
- }
- }
+ void setCheckedForSetup(boolean checked) {
+ mCheckedForSetup = checked;
}
CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
@@ -4544,9 +4523,18 @@
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivity", null);
// TODO: Switch to user app stacks here.
- return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
- resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
- profilerInfo, null, null, bOptions, false, userId, null, "startActivityAsUser");
+ return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
+ .setCaller(caller)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setResultTo(resultTo)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setStartFlags(startFlags)
+ .setProfilerInfo(profilerInfo)
+ .setMayWait(bOptions, userId)
+ .execute();
+
}
@Override
@@ -4607,11 +4595,17 @@
// TODO: Switch to user app stacks here.
try {
- int ret = mActivityStarter.startActivityMayWait(null, targetUid, targetPackage, intent,
- resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, null,
- null, null, bOptions, ignoreTargetSecurity, userId, null,
- "startActivityAsCaller");
- return ret;
+ return mActivityStartController.obtainStarter(intent, "startActivityAsCaller")
+ .setCallingUid(targetUid)
+ .setCallingPackage(targetPackage)
+ .setResolvedType(resolvedType)
+ .setResultTo(resultTo)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setStartFlags(startFlags)
+ .setMayWait(bOptions, userId)
+ .setIgnoreTargetSecurity(ignoreTargetSecurity)
+ .execute();
} catch (SecurityException e) {
// XXX need to figure out how to propagate to original app.
// A SecurityException here is generally actually a fault of the original
@@ -4637,9 +4631,18 @@
userId, false, ALLOW_FULL_ONLY, "startActivityAndWait", null);
WaitResult res = new WaitResult();
// TODO: Switch to user app stacks here.
- mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
- null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, res, null,
- bOptions, false, userId, null, "startActivityAndWait");
+ mActivityStartController.obtainStarter(intent, "startActivityAndWait")
+ .setCaller(caller)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setResultTo(resultTo)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setStartFlags(startFlags)
+ .setMayWait(bOptions, userId)
+ .setProfilerInfo(profilerInfo)
+ .setWaitResult(res)
+ .execute();
return res;
}
@@ -4651,10 +4654,17 @@
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivityWithConfig", null);
// TODO: Switch to user app stacks here.
- int ret = mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
- resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
- null, null, config, bOptions, false, userId, null, "startActivityWithConfig");
- return ret;
+ return mActivityStartController.obtainStarter(intent, "startActivityWithConfig")
+ .setCaller(caller)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setResultTo(resultTo)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setStartFlags(startFlags)
+ .setGlobalConfiguration(config)
+ .setMayWait(bOptions, userId)
+ .execute();
}
@Override
@@ -4700,9 +4710,16 @@
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
ALLOW_FULL_ONLY, "startVoiceActivity", null);
// TODO: Switch to user app stacks here.
- return mActivityStarter.startActivityMayWait(null, callingUid, callingPackage, intent,
- resolvedType, session, interactor, null, null, 0, startFlags, profilerInfo, null,
- null, bOptions, false, userId, null, "startVoiceActivity");
+ return mActivityStartController.obtainStarter(intent, "startVoiceActivity")
+ .setCallingUid(callingUid)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setVoiceSession(session)
+ .setVoiceInteractor(interactor)
+ .setStartFlags(startFlags)
+ .setProfilerInfo(profilerInfo)
+ .setMayWait(bOptions, userId)
+ .execute();
}
@Override
@@ -4711,9 +4728,13 @@
enforceCallingPermission(BIND_VOICE_INTERACTION, "startAssistantActivity()");
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
ALLOW_FULL_ONLY, "startAssistantActivity", null);
- return mActivityStarter.startActivityMayWait(null, callingUid, callingPackage, intent,
- resolvedType, null, null, null, null, 0, 0, null, null, null, bOptions, false,
- userId, null, "startAssistantActivity");
+
+ return mActivityStartController.obtainStarter(intent, "startAssistantActivity")
+ .setCallingUid(callingUid)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setMayWait(bOptions, userId)
+ .execute();
}
@Override
@@ -4753,9 +4774,12 @@
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(recentsComponent);
intent.putExtras(options);
- return mActivityStarter.startActivityMayWait(null, recentsUid, recentsPackage,
- intent, null, null, null, null, null, 0, 0, null, null, null, activityOptions,
- false, userId, null, "startRecentsActivity");
+
+ return mActivityStartController.obtainStarter(intent, "startRecentsActivity")
+ .setCallingUid(recentsUid)
+ .setCallingPackage(recentsPackage)
+ .setMayWait(activityOptions, userId)
+ .execute();
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -4928,11 +4952,22 @@
}
final long origId = Binder.clearCallingIdentity();
- int res = mActivityStarter.startActivityLocked(r.app.thread, intent,
- null /*ephemeralIntent*/, r.resolvedType, aInfo, null /*rInfo*/, null,
- null, resultTo != null ? resultTo.appToken : null, resultWho, requestCode, -1,
- r.launchedFromUid, r.launchedFromPackage, -1, r.launchedFromUid, 0, options,
- false, false, null, null, "startNextMatchingActivity");
+ // TODO(b/64750076): Check if calling pid should really be -1.
+ final int res = mActivityStartController
+ .obtainStarter(intent, "startNextMatchingActivity")
+ .setCaller(r.app.thread)
+ .setResolvedType(r.resolvedType)
+ .setActivityInfo(aInfo)
+ .setResultTo(resultTo != null ? resultTo.appToken : null)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setCallingPid(-1)
+ .setCallingUid(r.launchedFromUid)
+ .setCallingPackage(r.launchedFromPackage)
+ .setRealCallingPid(-1)
+ .setRealCallingUid(r.launchedFromUid)
+ .setActivityOptions(options)
+ .execute();
Binder.restoreCallingIdentity(origId);
r.finishing = wasFinishing;
@@ -4958,20 +4993,6 @@
}
}
- final int startActivityInPackage(int uid, String callingPackage,
- Intent intent, String resolvedType, IBinder resultTo,
- String resultWho, int requestCode, int startFlags, Bundle bOptions, int userId,
- TaskRecord inTask, String reason) {
-
- userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
- userId, false, ALLOW_FULL_ONLY, "startActivityInPackage", null);
-
- // TODO: Switch to user app stacks here.
- return mActivityStarter.startActivityMayWait(null, uid, callingPackage, intent,
- resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
- null, null, null, bOptions, false, userId, inTask, reason);
- }
-
@Override
public final int startActivities(IApplicationThread caller, String callingPackage,
Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions,
@@ -4981,21 +5002,8 @@
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, reason, null);
// TODO: Switch to user app stacks here.
- int ret = mActivityStarter.startActivities(caller, -1, callingPackage, intents,
- resolvedTypes, resultTo, bOptions, userId, reason);
- return ret;
- }
-
- final int startActivitiesInPackage(int uid, String callingPackage,
- Intent[] intents, String[] resolvedTypes, IBinder resultTo,
- Bundle bOptions, int userId) {
-
- final String reason = "startActivityInPackage";
- userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
- userId, false, ALLOW_FULL_ONLY, reason, null);
- // TODO: Switch to user app stacks here.
- int ret = mActivityStarter.startActivities(null, uid, callingPackage, intents, resolvedTypes,
- resultTo, bOptions, userId, reason);
+ int ret = mActivityStartController.startActivities(caller, -1, callingPackage,
+ intents, resolvedTypes, resultTo, bOptions, userId, reason);
return ret;
}
@@ -5121,7 +5129,8 @@
// because we don't support returning them across task boundaries. Also, to
// keep backwards compatibility we remove the task from recents when finishing
// task with root activity.
- res = mStackSupervisor.removeTaskByIdLocked(tr.taskId, false, finishWithRootActivity);
+ res = mStackSupervisor.removeTaskByIdLocked(tr.taskId, false,
+ finishWithRootActivity, "finish-activity");
if (!res) {
Slog.i(TAG, "Removing task failed to finish activity");
}
@@ -6648,7 +6657,7 @@
ProcessList.INVALID_ADJ, callerWillRestart, true, doit, evenPersistent,
packageName == null ? ("stop user " + userId) : ("stop " + packageName));
- didSomething |= mActivityStarter.clearPendingActivityLaunchesLocked(packageName);
+ didSomething |= mActivityStartController.clearPendingActivityLaunches(packageName);
if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
packageName, null, doit, evenPersistent, userId)) {
@@ -8607,6 +8616,16 @@
}
switch (appop) {
case AppOpsManager.MODE_ALLOWED:
+ // If force-background-check is enabled, restrict all apps that aren't whitelisted.
+ if (mForceBackgroundCheck &&
+ UserHandle.isApp(uid) &&
+ !isOnDeviceIdleWhitelistLocked(uid)) {
+ if (DEBUG_BACKGROUND_CHECK) {
+ Slog.i(TAG, "Force background check: " +
+ uid + "/" + packageName + " restricted");
+ }
+ return ActivityManager.APP_START_MODE_DELAYED;
+ }
return ActivityManager.APP_START_MODE_NORMAL;
case AppOpsManager.MODE_IGNORED:
return ActivityManager.APP_START_MODE_DELAYED;
@@ -8706,6 +8725,9 @@
return ActivityManager.APP_START_MODE_NORMAL;
}
+ /**
+ * @return whether a UID is in the system, user or temp doze whitelist.
+ */
boolean isOnDeviceIdleWhitelistLocked(int uid) {
final int appId = UserHandle.getAppId(uid);
return Arrays.binarySearch(mDeviceIdleWhitelist, appId) >= 0
@@ -8855,7 +8877,10 @@
final int callingAppId = UserHandle.getAppId(callingUid);
if ((callingAppId == SYSTEM_UID) || (callingAppId == ROOT_UID)) {
if ("com.android.settings.files".equals(grantUri.uri.getAuthority())) {
- // Exempted authority for cropping user photos in Settings app
+ // Exempted authority for
+ // 1. cropping user photos and sharing a generated license html
+ // file in Settings app
+ // 2. sharing a generated license html file in TvSettings app
} else {
Slog.w(TAG, "For security reasons, the system cannot issue a Uri permission"
+ " grant to " + grantUri + "; use startActivityAsCaller() instead");
@@ -9999,7 +10024,7 @@
}
}
- TaskRecord task = new TaskRecord(this,
+ TaskRecord task = TaskRecord.create(this,
mStackSupervisor.getNextTaskIdForUserLocked(r.userId),
ainfo, intent, description);
if (!mRecentTasks.addToBottom(task)) {
@@ -10299,7 +10324,8 @@
synchronized (this) {
final long ident = Binder.clearCallingIdentity();
try {
- return mStackSupervisor.removeTaskByIdLocked(taskId, true, REMOVE_FROM_RECENTS);
+ return mStackSupervisor.removeTaskByIdLocked(taskId, true, REMOVE_FROM_RECENTS,
+ "remove-task");
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -10468,7 +10494,7 @@
public void setTaskWindowingMode(int taskId, int windowingMode, boolean toTop) {
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
setTaskWindowingModeSplitScreenPrimary(taskId, SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT,
- toTop, ANIMATE, null /* initialBounds */);
+ toTop, ANIMATE, null /* initialBounds */, true /* showRecents */);
return;
}
enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setTaskWindowingMode()");
@@ -10489,12 +10515,12 @@
+ " non-standard task " + taskId + " to windowing mode="
+ windowingMode);
}
- final ActivityDisplay display = task.getStack().getDisplay();
- final ActivityStack stack = display.getOrCreateStack(windowingMode,
- task.getStack().getActivityType(), toTop);
- // TODO: Use ActivityStack.setWindowingMode instead of re-parenting.
- task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME,
- "moveTaskToStack");
+
+ final ActivityStack stack = task.getStack();
+ if (toTop) {
+ stack.moveToFront("setTaskWindowingMode", task);
+ }
+ stack.setWindowingMode(windowingMode);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -10514,10 +10540,12 @@
* @param animate Whether we should play an animation for the moving the task.
* @param initialBounds If the primary stack gets created, it will use these bounds for the
* stack. Pass {@code null} to use default bounds.
+ * @param showRecents If the recents activity should be shown on the other side of the task
+ * going into split-screen mode.
*/
@Override
public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop,
- boolean animate, Rect initialBounds) {
+ boolean animate, Rect initialBounds, boolean showRecents) {
enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
"setTaskWindowingModeSplitScreenPrimary()");
synchronized (this) {
@@ -10542,7 +10570,8 @@
if (toTop) {
stack.moveToFront("setTaskWindowingModeSplitScreenPrimary", task);
}
- stack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, animate);
+ stack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, animate, showRecents,
+ true /* sendNonResizeableNotification */);
return windowingMode != task.getWindowingMode();
} finally {
Binder.restoreCallingIdentity(ident);
@@ -11722,6 +11751,10 @@
return AppGlobals.getPackageManager();
}
+ ActivityStartController getActivityStartController() {
+ return mActivityStartController;
+ }
+
PackageManagerInternal getPackageManagerInternalLocked() {
if (mPackageManagerInt == null) {
mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);
@@ -12571,7 +12604,16 @@
synchronized (this) {
final long ident = Binder.clearCallingIdentity();
try {
- mActivityStarter.startConfirmCredentialIntent(intent, options);
+ intent.addFlags(FLAG_ACTIVITY_NEW_TASK |
+ FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
+ FLAG_ACTIVITY_TASK_ON_HOME);
+ ActivityOptions activityOptions = options != null
+ ? new ActivityOptions(options)
+ : ActivityOptions.makeBasic();
+ activityOptions.setLaunchTaskId(
+ mStackSupervisor.getHomeActivity().getTask().taskId);
+ mContext.startActivityAsUser(intent, activityOptions.toBundle(),
+ UserHandle.CURRENT);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -12590,9 +12632,7 @@
mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
+ APP_SWITCH_DELAY_TIME;
mDidAppSwitch = false;
- mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
- Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
- mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
+ mActivityStartController.schedulePendingActivityLaunches(APP_SWITCH_DELAY_TIME);
}
}
@@ -12611,6 +12651,18 @@
}
}
+ boolean checkAllowAppSwitchUid(int uid) {
+ ArrayMap<String, Integer> types = mAllowAppSwitchUids.get(UserHandle.getUserId(uid));
+ if (types != null) {
+ for (int i = types.size() - 1; i >= 0; i--) {
+ if (types.valueAt(i).intValue() == uid) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
int callingPid, int callingUid, String name) {
if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
@@ -12623,6 +12675,9 @@
if (perm == PackageManager.PERMISSION_GRANTED) {
return true;
}
+ if (checkAllowAppSwitchUid(sourceUid)) {
+ return true;
+ }
// If the actual IPC caller is different from the logical source, then
// also see if they are allowed to control app switches.
@@ -12633,6 +12688,9 @@
if (perm == PackageManager.PERMISSION_GRANTED) {
return true;
}
+ if (checkAllowAppSwitchUid(callingUid)) {
+ return true;
+ }
}
Slog.w(TAG, name + " request from " + sourceUid + " stopped");
@@ -13645,7 +13703,8 @@
stats.getPackageStatsLocked(sourceUid >= 0 ? sourceUid : uid,
sourcePkg != null ? sourcePkg : rec.key.packageName);
pkg.noteWakeupAlarmLocked(tag);
- StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, sourceUid >= 0 ? sourceUid : uid);
+ StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, sourceUid >= 0 ? sourceUid : uid,
+ tag);
}
}
}
@@ -14144,6 +14203,16 @@
readGrantedUriPermissionsLocked();
}
+ final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
+ if (pmi != null) {
+ pmi.registerLowPowerModeObserver(ServiceType.FORCE_BACKGROUND_CHECK,
+ state -> updateForceBackgroundCheck(state.batterySaverEnabled));
+ updateForceBackgroundCheck(
+ pmi.getLowPowerState(ServiceType.FORCE_BACKGROUND_CHECK).batterySaverEnabled);
+ } else {
+ Slog.wtf(TAG, "PowerManagerInternal not found.");
+ }
+
if (goingCallback != null) goingCallback.run();
traceLog.traceBegin("ActivityManagerStartApps");
mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_RUNNING_START,
@@ -14242,6 +14311,23 @@
}
}
+ private void updateForceBackgroundCheck(boolean enabled) {
+ synchronized (this) {
+ if (mForceBackgroundCheck != enabled) {
+ mForceBackgroundCheck = enabled;
+
+ if (DEBUG_BACKGROUND_CHECK) {
+ Slog.i(TAG, "Force background check " + (enabled ? "enabled" : "disabled"));
+ }
+
+ if (mForceBackgroundCheck) {
+ // Stop background services for idle UIDs.
+ doStopUidForIdleUidsLocked();
+ }
+ }
+ }
+ }
+
void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog) {
synchronized (this) {
mAppErrors.killAppAtUserRequestLocked(app, fromDialog);
@@ -14517,7 +14603,7 @@
try {
PackageInfo pi = pm.getPackageInfo(pkg, 0, UserHandle.getCallingUserId());
if (pi != null) {
- sb.append(" v").append(pi.versionCode);
+ sb.append(" v").append(pi.getLongVersionCode());
if (pi.versionName != null) {
sb.append(" (").append(pi.versionName).append(")");
}
@@ -14909,6 +14995,7 @@
boolean dumpVisibleStacksOnly = false;
boolean dumpFocusedStackOnly = false;
String dumpPackage = null;
+ int dumpAppId = -1;
int opti = 0;
while (opti < args.length) {
@@ -15003,6 +15090,16 @@
return;
}
+ if (dumpPackage != null) {
+ try {
+ ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
+ dumpPackage, 0);
+ dumpAppId = UserHandle.getAppId(info.uid);
+ } catch (NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+
boolean more = false;
// Is the caller requesting to dump a particular piece of data?
if (opti < args.length) {
@@ -15110,7 +15207,7 @@
args.length - opti);
}
synchronized (this) {
- dumpProcessesLocked(fd, pw, args, opti, true, dumpPackage);
+ dumpProcessesLocked(fd, pw, args, opti, true, dumpPackage, dumpAppId);
}
} else if ("oom".equals(cmd) || "o".equals(cmd)) {
synchronized (this) {
@@ -15296,7 +15393,7 @@
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
- dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+ dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId);
}
} else {
@@ -15373,7 +15470,7 @@
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
- dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+ dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId);
}
}
Binder.restoreCallingIdentity(origId);
@@ -15401,7 +15498,7 @@
private void dumpActivityStarterLocked(PrintWriter pw, String dumpPackage) {
pw.println("ACTIVITY MANAGER STARTER (dumpsys activity starter)");
- mActivityStarter.dump(pw, "", dumpPackage);
+ mActivityStartController.dump(pw, "", dumpPackage);
}
void dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
@@ -15528,22 +15625,12 @@
}
}
- boolean dumpUids(PrintWriter pw, String dumpPackage, SparseArray<UidRecord> uids,
+ boolean dumpUids(PrintWriter pw, String dumpPackage, int dumpAppId, SparseArray<UidRecord> uids,
String header, boolean needSep) {
boolean printed = false;
- int whichAppId = -1;
- if (dumpPackage != null) {
- try {
- ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
- dumpPackage, 0);
- whichAppId = UserHandle.getAppId(info.uid);
- } catch (NameNotFoundException e) {
- e.printStackTrace();
- }
- }
for (int i=0; i<uids.size(); i++) {
UidRecord uidRec = uids.valueAt(i);
- if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) {
+ if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != dumpAppId) {
continue;
}
if (!printed) {
@@ -15590,9 +15677,8 @@
}
void dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
- int opti, boolean dumpAll, String dumpPackage) {
+ int opti, boolean dumpAll, String dumpPackage, int dumpAppId) {
boolean needSep = false;
- boolean printedAnything = false;
int numPers = 0;
pw.println("ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)");
@@ -15610,7 +15696,6 @@
if (!needSep) {
pw.println(" All known processes:");
needSep = true;
- printedAnything = true;
}
pw.print(r.persistent ? " *PERS*" : " *APP*");
pw.print(" UID "); pw.print(procs.keyAt(ia));
@@ -15635,7 +15720,6 @@
pw.println();
}
pw.println(" Isolated process list (sorted by uid):");
- printedAnything = true;
printed = true;
needSep = true;
}
@@ -15657,7 +15741,6 @@
pw.println();
}
pw.println(" Active instrumentation:");
- printedAnything = true;
printed = true;
needSep = true;
}
@@ -15668,14 +15751,15 @@
}
if (mActiveUids.size() > 0) {
- if (dumpUids(pw, dumpPackage, mActiveUids, "UID states:", needSep)) {
- printedAnything = needSep = true;
+ if (dumpUids(pw, dumpPackage, dumpAppId, mActiveUids, "UID states:", needSep)) {
+ needSep = true;
}
}
if (dumpAll) {
if (mValidateUids.size() > 0) {
- if (dumpUids(pw, dumpPackage, mValidateUids, "UID validation:", needSep)) {
- printedAnything = needSep = true;
+ if (dumpUids(pw, dumpPackage, dumpAppId, mValidateUids, "UID validation:",
+ needSep)) {
+ needSep = true;
}
}
}
@@ -15692,7 +15776,6 @@
pw.println("):");
dumpProcessOomList(pw, this, mLruProcesses, " ", "Proc", "PERS", false, dumpPackage);
needSep = true;
- printedAnything = true;
}
if (dumpAll || dumpPackage != null) {
@@ -15708,7 +15791,6 @@
needSep = true;
pw.println(" PID mappings:");
printed = true;
- printedAnything = true;
}
pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
@@ -15731,7 +15813,6 @@
needSep = true;
pw.println(" Foreground Processes:");
printed = true;
- printedAnything = true;
}
pw.print(" PID #"); pw.print(mImportantProcesses.keyAt(i));
pw.print(": "); pw.println(mImportantProcesses.valueAt(i));
@@ -15742,7 +15823,6 @@
if (mPersistentStartingProcesses.size() > 0) {
if (needSep) pw.println();
needSep = true;
- printedAnything = true;
pw.println(" Persisent processes that are starting:");
dumpProcessList(pw, this, mPersistentStartingProcesses, " ",
"Starting Norm", "Restarting PERS", dumpPackage);
@@ -15751,7 +15831,6 @@
if (mRemovedProcesses.size() > 0) {
if (needSep) pw.println();
needSep = true;
- printedAnything = true;
pw.println(" Processes that are being removed:");
dumpProcessList(pw, this, mRemovedProcesses, " ",
"Removed Norm", "Removed PERS", dumpPackage);
@@ -15760,7 +15839,6 @@
if (mProcessesOnHold.size() > 0) {
if (needSep) pw.println();
needSep = true;
- printedAnything = true;
pw.println(" Processes that are on old until the system is ready:");
dumpProcessList(pw, this, mProcessesOnHold, " ",
"OnHold Norm", "OnHold PERS", dumpPackage);
@@ -15769,9 +15847,6 @@
needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll, dumpPackage);
needSep = mAppErrors.dumpLocked(fd, pw, needSep, dumpPackage);
- if (needSep) {
- printedAnything = true;
- }
if (dumpPackage == null) {
pw.println();
@@ -15978,6 +16053,32 @@
pw.println(" mNativeDebuggingApp=" + mNativeDebuggingApp);
}
}
+ if (mAllowAppSwitchUids.size() > 0) {
+ boolean printed = false;
+ for (int i = 0; i < mAllowAppSwitchUids.size(); i++) {
+ ArrayMap<String, Integer> types = mAllowAppSwitchUids.valueAt(i);
+ for (int j = 0; j < types.size(); j++) {
+ if (dumpPackage == null ||
+ UserHandle.getAppId(types.valueAt(j).intValue()) == dumpAppId) {
+ if (needSep) {
+ pw.println();
+ needSep = false;
+ }
+ if (!printed) {
+ pw.println(" mAllowAppSwitchUids:");
+ printed = true;
+ }
+ pw.print(" User ");
+ pw.print(mAllowAppSwitchUids.keyAt(i));
+ pw.print(": Type ");
+ pw.print(types.keyAt(j));
+ pw.print(" = ");
+ UserHandle.formatUid(pw, types.valueAt(j).intValue());
+ pw.println();
+ }
+ }
+ }
+ }
if (dumpPackage == null) {
if (mAlwaysFinishActivities) {
pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities);
@@ -16017,10 +16118,7 @@
pw.println();
}
}
-
- if (!printedAnything) {
- pw.println(" (nothing)");
- }
+ pw.println(" mForceBackgroundCheck=" + mForceBackgroundCheck);
}
boolean dumpProcessesToGc(FileDescriptor fd, PrintWriter pw, String[] args,
@@ -17117,8 +17215,8 @@
boolean dumpProto;
}
- final void dumpApplicationMemoryUsage(FileDescriptor fd,
- PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) {
+ final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw, String prefix,
+ String[] args, boolean brief, PrintWriter categoryPw, boolean asProto) {
MemoryUsageDumpOptions opts = new MemoryUsageDumpOptions();
opts.dumpDetails = false;
opts.dumpFullDetails = false;
@@ -17131,7 +17229,7 @@
opts.packages = false;
opts.isCheckinRequest = false;
opts.dumpSwapPss = false;
- opts.dumpProto = false;
+ opts.dumpProto = asProto;
int opti = 0;
while (opti < args.length) {
@@ -17199,7 +17297,7 @@
}
}
- final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw, String prefix,
+ private final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw, String prefix,
MemoryUsageDumpOptions opts, String[] innerArgs, boolean brief,
ArrayList<ProcessRecord> procs, PrintWriter categoryPw) {
long uptime = SystemClock.uptimeMillis();
@@ -17208,54 +17306,59 @@
if (procs == null) {
// No Java processes. Maybe they want to print a native process.
- if (innerArgs.length > 0 && innerArgs[0].charAt(0) != '-') {
- ArrayList<ProcessCpuTracker.Stats> nativeProcs
- = new ArrayList<ProcessCpuTracker.Stats>();
- updateCpuStatsNow();
- int findPid = -1;
- try {
- findPid = Integer.parseInt(innerArgs[0]);
- } catch (NumberFormatException e) {
- }
- synchronized (mProcessCpuTracker) {
- final int N = mProcessCpuTracker.countStats();
- for (int i=0; i<N; i++) {
- ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
- if (st.pid == findPid || (st.baseName != null
- && st.baseName.equals(innerArgs[0]))) {
- nativeProcs.add(st);
+ String proc = "N/A";
+ if (innerArgs.length > 0) {
+ proc = innerArgs[0];
+ if (proc.charAt(0) != '-') {
+ ArrayList<ProcessCpuTracker.Stats> nativeProcs
+ = new ArrayList<ProcessCpuTracker.Stats>();
+ updateCpuStatsNow();
+ int findPid = -1;
+ try {
+ findPid = Integer.parseInt(innerArgs[0]);
+ } catch (NumberFormatException e) {
+ }
+ synchronized (mProcessCpuTracker) {
+ final int N = mProcessCpuTracker.countStats();
+ for (int i=0; i<N; i++) {
+ ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+ if (st.pid == findPid || (st.baseName != null
+ && st.baseName.equals(innerArgs[0]))) {
+ nativeProcs.add(st);
+ }
}
}
- }
- if (nativeProcs.size() > 0) {
- dumpApplicationMemoryUsageHeader(pw, uptime, realtime, opts.isCheckinRequest,
- opts.isCompact);
- Debug.MemoryInfo mi = null;
- for (int i = nativeProcs.size() - 1 ; i >= 0 ; i--) {
- final ProcessCpuTracker.Stats r = nativeProcs.get(i);
- final int pid = r.pid;
- if (!opts.isCheckinRequest && opts.dumpDetails) {
- pw.println("\n** MEMINFO in pid " + pid + " [" + r.baseName + "] **");
+ if (nativeProcs.size() > 0) {
+ dumpApplicationMemoryUsageHeader(pw, uptime, realtime,
+ opts.isCheckinRequest, opts.isCompact);
+ Debug.MemoryInfo mi = null;
+ for (int i = nativeProcs.size() - 1 ; i >= 0 ; i--) {
+ final ProcessCpuTracker.Stats r = nativeProcs.get(i);
+ final int pid = r.pid;
+ if (!opts.isCheckinRequest && opts.dumpDetails) {
+ pw.println("\n** MEMINFO in pid " + pid + " [" + r.baseName + "] **");
+ }
+ if (mi == null) {
+ mi = new Debug.MemoryInfo();
+ }
+ if (opts.dumpDetails || (!brief && !opts.oomOnly)) {
+ Debug.getMemoryInfo(pid, mi);
+ } else {
+ mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null);
+ mi.dalvikPrivateDirty = (int)tmpLong[0];
+ }
+ ActivityThread.dumpMemInfoTable(pw, mi, opts.isCheckinRequest,
+ opts.dumpFullDetails, opts.dumpDalvik, opts.dumpSummaryOnly,
+ pid, r.baseName, 0, 0, 0, 0, 0, 0);
+ if (opts.isCheckinRequest) {
+ pw.println();
+ }
}
- if (mi == null) {
- mi = new Debug.MemoryInfo();
- }
- if (opts.dumpDetails || (!brief && !opts.oomOnly)) {
- Debug.getMemoryInfo(pid, mi);
- } else {
- mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null);
- mi.dalvikPrivateDirty = (int)tmpLong[0];
- }
- ActivityThread.dumpMemInfoTable(pw, mi, opts.isCheckinRequest, opts.dumpFullDetails,
- opts.dumpDalvik, opts.dumpSummaryOnly, pid, r.baseName, 0, 0, 0, 0, 0, 0);
- if (opts.isCheckinRequest) {
- pw.println();
- }
+ return;
}
- return;
}
}
- pw.println("No process found for: " + innerArgs[0]);
+ pw.println("No process found for: " + proc);
return;
}
@@ -17678,15 +17781,77 @@
}
}
- final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw,
+ private final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw,
MemoryUsageDumpOptions opts, String[] innerArgs, boolean brief,
ArrayList<ProcessRecord> procs) {
- ProtoOutputStream proto = new ProtoOutputStream(fd);
+ final long uptimeMs = SystemClock.uptimeMillis();
+ final long realtimeMs = SystemClock.elapsedRealtime();
+ final long[] tmpLong = new long[1];
- // TODO: implement
- pw.println("Not yet implemented. Have a cookie instead! :]");
+ if (procs == null) {
+ // No Java processes. Maybe they want to print a native process.
+ String proc = "N/A";
+ if (innerArgs.length > 0) {
+ proc = innerArgs[0];
+ if (proc.charAt(0) != '-') {
+ ArrayList<ProcessCpuTracker.Stats> nativeProcs
+ = new ArrayList<ProcessCpuTracker.Stats>();
+ updateCpuStatsNow();
+ int findPid = -1;
+ try {
+ findPid = Integer.parseInt(innerArgs[0]);
+ } catch (NumberFormatException e) {
+ }
+ synchronized (mProcessCpuTracker) {
+ final int N = mProcessCpuTracker.countStats();
+ for (int i=0; i<N; i++) {
+ ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+ if (st.pid == findPid || (st.baseName != null
+ && st.baseName.equals(innerArgs[0]))) {
+ nativeProcs.add(st);
+ }
+ }
+ }
+ if (nativeProcs.size() > 0) {
+ ProtoOutputStream proto = new ProtoOutputStream(fd);
- proto.flush();
+ proto.write(MemInfoProto.UPTIME_DURATION_MS, uptimeMs);
+ proto.write(MemInfoProto.ELAPSED_REALTIME_MS, realtimeMs);
+ Debug.MemoryInfo mi = null;
+ for (int i = nativeProcs.size() - 1 ; i >= 0 ; i--) {
+ final ProcessCpuTracker.Stats r = nativeProcs.get(i);
+ final int pid = r.pid;
+ final long nToken = proto.start(MemInfoProto.NATIVE_PROCESSES);
+
+ proto.write(MemInfoProto.NativeProcess.PID, pid);
+ proto.write(MemInfoProto.NativeProcess.PROCESS_NAME, r.baseName);
+
+ if (mi == null) {
+ mi = new Debug.MemoryInfo();
+ }
+ if (opts.dumpDetails || (!brief && !opts.oomOnly)) {
+ Debug.getMemoryInfo(pid, mi);
+ } else {
+ mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null);
+ mi.dalvikPrivateDirty = (int)tmpLong[0];
+ }
+ ActivityThread.dumpMemInfoTable(proto, mi, opts.dumpDalvik,
+ opts.dumpSummaryOnly, 0, 0, 0, 0, 0, 0);
+
+ proto.end(nToken);
+ }
+
+ proto.flush();
+ return;
+ }
+ }
+ }
+ Log.d(TAG, "No process found for: " + innerArgs[0]);
+ return;
+ }
+
+ // TODO: finish
+ pw.println("Java processes aren't implemented yet. Have a coffee instead! :]");
}
private void appendBasicMemEntry(StringBuilder sb, int oomAdj, int procState, long pss,
@@ -17956,7 +18121,7 @@
PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
String[] emptyArgs = new String[] { };
catPw.println();
- dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null);
+ dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null, -1);
catPw.println();
mServices.newServiceDumperLocked(null, catPw, emptyArgs, 0,
false, null).dumpLocked();
@@ -20064,6 +20229,11 @@
// Instrumentation can kill and relaunch even persistent processes
forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, false, userId,
"start instr");
+ // Inform usage stats to make the target package active
+ if (mUsageStatsService != null) {
+ mUsageStatsService.reportEvent(ii.targetPackage, userId,
+ UsageEvents.Event.SYSTEM_INTERACTION);
+ }
ProcessRecord app = addAppLocked(ai, defProcess, false, abiOverride);
app.instr = activeInstr;
activeInstr.mFinished = false;
@@ -20509,9 +20679,11 @@
if (app.thread != null) {
if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
+ app.processName + " new config " + configCopy);
- app.thread.scheduleConfigurationChanged(configCopy);
+ mLifecycleManager.scheduleTransaction(app.thread,
+ ConfigurationChangeItem.obtain(configCopy));
}
} catch (Exception e) {
+ Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change", e);
}
}
@@ -23279,6 +23451,24 @@
}
}
+ /**
+ * Call {@link #doStopUidLocked} (which will also stop background services) for all idle UIDs.
+ */
+ void doStopUidForIdleUidsLocked() {
+ final int size = mActiveUids.size();
+ for (int i = 0; i < size; i++) {
+ final int uid = mActiveUids.keyAt(i);
+ if (!UserHandle.isApp(uid)) {
+ continue;
+ }
+ final UidRecord uidRec = mActiveUids.valueAt(i);
+ if (!uidRec.idle) {
+ continue;
+ }
+ doStopUidLocked(uidRec.uid, uidRec);
+ }
+ }
+
final void doStopUidLocked(int uid, final UidRecord uidRec) {
mServices.stopInBackgroundLocked(uid);
enqueueUidChangeLocked(uidRec, uid, UidRecord.CHANGE_IDLE);
@@ -23700,7 +23890,13 @@
*/
@Override
public boolean startUserInBackground(final int userId) {
- return mUserController.startUser(userId, /* foreground */ false);
+ return startUserInBackgroundWithListener(userId, null);
+ }
+
+ @Override
+ public boolean startUserInBackgroundWithListener(final int userId,
+ @Nullable IProgressListener unlockListener) {
+ return mUserController.startUser(userId, /* foreground */ false, unlockListener);
}
@Override
@@ -24070,8 +24266,8 @@
}
synchronized (ActivityManagerService.this) {
- return startActivitiesInPackage(packageUid, packageName, intents, resolvedTypes,
- /*resultTo*/ null, bOptions, userId);
+ return mActivityStartController.startActivitiesInPackage(packageUid, packageName,
+ intents, resolvedTypes, /*resultTo*/ null, bOptions, userId);
}
}
@@ -24222,7 +24418,7 @@
pw.println(" Reason: " + reason);
}
pw.println();
- mActivityStarter.dump(pw, " ", null);
+ mActivityStartController.dump(pw, " ", null);
pw.println();
pw.println("-------------------------------------------------------------------------------");
dumpActivitiesLocked(null /* fd */, pw, null /* args */, 0 /* opti */,
@@ -24256,6 +24452,32 @@
}
}
}
+
+ @Override
+ public void setAllowAppSwitches(@NonNull String type, int uid, int userId) {
+ synchronized (ActivityManagerService.this) {
+ if (mUserController.isUserRunning(userId, ActivityManager.FLAG_OR_STOPPED)) {
+ ArrayMap<String, Integer> types = mAllowAppSwitchUids.get(userId);
+ if (types == null) {
+ if (uid < 0) {
+ return;
+ }
+ types = new ArrayMap<>();
+ mAllowAppSwitchUids.put(userId, types);
+ }
+ if (uid < 0) {
+ types.remove(type);
+ } else {
+ types.put(type, uid);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean isRuntimeRestarted() {
+ return mSystemServiceManager.isRuntimeRestarted();
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 7eb922c..979323f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -224,6 +224,8 @@
return runGetInactive(pw);
case "set-standby-bucket":
return runSetStandbyBucket(pw);
+ case "get-standby-bucket":
+ return runGetStandbyBucket(pw);
case "send-trim-memory":
return runSendTrimMemory(pw);
case "display":
@@ -1826,6 +1828,29 @@
return 0;
}
+ private int bucketNameToBucketValue(String name) {
+ String lower = name.toLowerCase();
+ if (lower.startsWith("ac")) {
+ return UsageStatsManager.STANDBY_BUCKET_ACTIVE;
+ } else if (lower.startsWith("wo")) {
+ return UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
+ } else if (lower.startsWith("fr")) {
+ return UsageStatsManager.STANDBY_BUCKET_FREQUENT;
+ } else if (lower.startsWith("ra")) {
+ return UsageStatsManager.STANDBY_BUCKET_RARE;
+ } else if (lower.startsWith("ne")) {
+ return UsageStatsManager.STANDBY_BUCKET_NEVER;
+ } else {
+ try {
+ int bucket = Integer.parseInt(lower);
+ return bucket;
+ } catch (NumberFormatException nfe) {
+ getErrPrintWriter().println("Error: Unknown bucket: " + name);
+ }
+ }
+ return -1;
+ }
+
int runSetStandbyBucket(PrintWriter pw) throws RemoteException {
int userId = UserHandle.USER_CURRENT;
@@ -1840,10 +1865,33 @@
}
String packageName = getNextArgRequired();
String value = getNextArgRequired();
+ int bucket = bucketNameToBucketValue(value);
+ if (bucket < 0) return -1;
IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService(
Context.USAGE_STATS_SERVICE));
- usm.setAppStandbyBucket(packageName, Integer.parseInt(value), userId);
+ usm.setAppStandbyBucket(packageName, bucketNameToBucketValue(value), userId);
+ return 0;
+ }
+
+ int runGetStandbyBucket(PrintWriter pw) throws RemoteException {
+ int userId = UserHandle.USER_CURRENT;
+
+ String opt;
+ while ((opt=getNextOption()) != null) {
+ if (opt.equals("--user")) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ } else {
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+ String packageName = getNextArgRequired();
+
+ IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService(
+ Context.USAGE_STATS_SERVICE));
+ int bucket = usm.getAppStandbyBucket(packageName, null, userId);
+ pw.println(bucket);
return 0;
}
@@ -2597,8 +2645,10 @@
pw.println(" Sets the inactive state of an app.");
pw.println(" get-inactive [--user <USER_ID>] <PACKAGE>");
pw.println(" Returns the inactive state of an app.");
- pw.println(" set-standby-bucket [--user <USER_ID>] <PACKAGE> <BUCKET>");
+ pw.println(" set-standby-bucket [--user <USER_ID>] <PACKAGE> active|working_set|frequent|rare");
pw.println(" Puts an app in the standby bucket.");
+ pw.println(" get-standby-bucket [--user <USER_ID>] <PACKAGE>");
+ pw.println(" Returns the standby bucket of an app.");
pw.println(" send-trim-memory [--user <USER_ID>] <PROCESS>");
pw.println(" [HIDDEN|RUNNING_MODERATE|BACKGROUND|RUNNING_LOW|MODERATE|RUNNING_CRITICAL|COMPLETE]");
pw.println(" Send a memory trim event to a <PROCESS>. May also supply a raw trim int level.");
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 11590d6..60a6236 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -131,6 +131,12 @@
import android.app.PendingIntent;
import android.app.PictureInPictureParams;
import android.app.ResultInfo;
+import android.app.servertransaction.MoveToDisplayItem;
+import android.app.servertransaction.MultiWindowModeChangeItem;
+import android.app.servertransaction.NewIntentItem;
+import android.app.servertransaction.PipModeChangeItem;
+import android.app.servertransaction.WindowVisibilityItem;
+import android.app.servertransaction.ActivityConfigurationChangeItem;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -611,8 +617,8 @@
"Reporting activity moved to display" + ", activityRecord=" + this
+ ", displayId=" + displayId + ", config=" + config);
- app.thread.scheduleActivityMovedToDisplay(appToken, displayId,
- new Configuration(config));
+ service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ MoveToDisplayItem.obtain(displayId, config));
} catch (RemoteException e) {
// If process died, whatever.
}
@@ -629,7 +635,8 @@
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + this + ", config: "
+ config);
- app.thread.scheduleActivityConfigurationChanged(appToken, new Configuration(config));
+ service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ ActivityConfigurationChangeItem.obtain(config));
} catch (RemoteException e) {
// If process died, whatever.
}
@@ -640,8 +647,13 @@
return;
}
+ if (task.getStack().deferScheduleMultiWindowModeChanged()) {
+ // Don't do anything if we are currently deferring multi-window mode change.
+ return;
+ }
+
// An activity is considered to be in multi-window mode if its task isn't fullscreen.
- final boolean inMultiWindowMode = task.inMultiWindowMode();
+ final boolean inMultiWindowMode = inMultiWindowMode();
if (inMultiWindowMode != mLastReportedMultiWindowMode) {
mLastReportedMultiWindowMode = inMultiWindowMode;
scheduleMultiWindowModeChanged(getConfiguration());
@@ -650,8 +662,9 @@
private void scheduleMultiWindowModeChanged(Configuration overrideConfig) {
try {
- app.thread.scheduleMultiWindowModeChanged(appToken, mLastReportedMultiWindowMode,
- overrideConfig);
+ service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ MultiWindowModeChangeItem.obtain(mLastReportedMultiWindowMode,
+ overrideConfig));
} catch (Exception e) {
// If process died, I don't care.
}
@@ -667,7 +680,7 @@
// Picture-in-picture mode changes also trigger a multi-window mode change as well, so
// update that here in order
mLastReportedPictureInPictureMode = inPictureInPictureMode;
- mLastReportedMultiWindowMode = inPictureInPictureMode;
+ mLastReportedMultiWindowMode = inMultiWindowMode();
final Configuration newConfig = task.computeNewOverrideConfigurationForBounds(
targetStackBounds, null);
schedulePictureInPictureModeChanged(newConfig);
@@ -677,8 +690,9 @@
private void schedulePictureInPictureModeChanged(Configuration overrideConfig) {
try {
- app.thread.schedulePictureInPictureModeChanged(appToken,
- mLastReportedPictureInPictureMode, overrideConfig);
+ service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ PipModeChangeItem.obtain(mLastReportedPictureInPictureMode,
+ overrideConfig));
} catch (Exception e) {
// If process died, no one cares.
}
@@ -1365,8 +1379,8 @@
try {
ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
ar.add(rintent);
- app.thread.scheduleNewIntent(
- ar, appToken, state == PAUSED /* andPause */);
+ service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ NewIntentItem.obtain(ar, state == PAUSED));
unsent = false;
} catch (RemoteException e) {
Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
@@ -1588,7 +1602,8 @@
setVisible(true);
sleeping = false;
app.pendingUiClean = true;
- app.thread.scheduleWindowVisibility(appToken, true /* showWindow */);
+ service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ WindowVisibilityItem.obtain(true /* showWindow */));
// The activity may be waiting for stop, but that is no longer appropriate for it.
mStackSupervisor.mStoppingActivities.remove(this);
mStackSupervisor.mGoingToSleepActivities.remove(this);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 4816998..cf40be5 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -104,6 +104,13 @@
import android.app.ResultInfo;
import android.app.WindowConfiguration.ActivityType;
import android.app.WindowConfiguration.WindowingMode;
+import android.app.servertransaction.ActivityResultItem;
+import android.app.servertransaction.NewIntentItem;
+import android.app.servertransaction.WindowVisibilityItem;
+import android.app.servertransaction.DestroyActivityItem;
+import android.app.servertransaction.PauseActivityItem;
+import android.app.servertransaction.ResumeActivityItem;
+import android.app.servertransaction.StopActivityItem;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -137,6 +144,7 @@
import com.android.internal.os.BatteryStatsImpl;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService.ItemMatcher;
+import com.android.server.am.EventLogTags;
import com.android.server.wm.ConfigurationContainer;
import com.android.server.wm.StackWindowController;
import com.android.server.wm.StackWindowListener;
@@ -475,10 +483,12 @@
@Override
public void setWindowingMode(int windowingMode) {
- setWindowingMode(windowingMode, false /* animate */);
+ setWindowingMode(windowingMode, false /* animate */, true /* showRecents */,
+ true /* sendNonResizeableNotification */);
}
- void setWindowingMode(int preferredWindowingMode, boolean animate) {
+ void setWindowingMode(int preferredWindowingMode, boolean animate, boolean showRecents,
+ boolean sendNonResizeableNotification) {
final int currentMode = getWindowingMode();
final ActivityDisplay display = getDisplay();
final TaskRecord topTask = topTask();
@@ -487,16 +497,19 @@
// Need to make sure windowing mode is supported.
int windowingMode = display.resolveWindowingMode(
- null /* ActivityRecord */, mTmpOptions, topTask, getActivityType());;
+ null /* ActivityRecord */, mTmpOptions, topTask, getActivityType());
if (splitScreenStack == this && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
// Resolution to split-screen secondary for the primary split-screen stack means we want
// to go fullscreen.
windowingMode = WINDOWING_MODE_FULLSCREEN;
}
+ final boolean alreadyInSplitScreenMode = display.hasSplitScreenPrimaryStack();
+
// Take any required action due to us not supporting the preferred windowing mode.
- if (windowingMode != preferredWindowingMode && isActivityTypeStandardOrUndefined()) {
- if (display.hasSplitScreenPrimaryStack()
+ if (sendNonResizeableNotification
+ && windowingMode != preferredWindowingMode && isActivityTypeStandardOrUndefined()) {
+ if (alreadyInSplitScreenMode
&& (preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
|| preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)) {
// Looks like we can't launch in split screen mode, go ahead an dismiss split-screen
@@ -514,8 +527,9 @@
final WindowManagerService wm = mService.mWindowManager;
final ActivityRecord topActivity = getTopActivity();
- if (windowingMode != WINDOWING_MODE_FULLSCREEN && topActivity != null
- && topActivity.isNonResizableOrForcedResizable() && !topActivity.noDisplay) {
+ if (sendNonResizeableNotification && windowingMode != WINDOWING_MODE_FULLSCREEN
+ && topActivity != null && topActivity.isNonResizableOrForcedResizable()
+ && !topActivity.noDisplay) {
// Inform the user that they are starting an app that may not work correctly in
// multi-window mode.
final String packageName = topActivity.appInfo.packageName;
@@ -570,7 +584,7 @@
resize(mTmpRect2, null /* tempTaskBounds */, null /* tempTaskInsetBounds */);
}
} finally {
- if (mDisplayId == DEFAULT_DISPLAY
+ if (showRecents && !alreadyInSplitScreenMode && mDisplayId == DEFAULT_DISPLAY
&& windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
// Make sure recents stack exist when creating a dock stack as it normally needs to
// be on the other side of the docked stack and we make visibility decisions based
@@ -1415,12 +1429,13 @@
if (prev.app != null && prev.app.thread != null) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
try {
- EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
- prev.userId, System.identityHashCode(prev),
- prev.shortComponentName);
+ EventLogTags.writeAmPauseActivity(prev.userId, System.identityHashCode(prev),
+ prev.shortComponentName, "userLeaving=" + userLeaving);
mService.updateUsageStats(prev, false);
- prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
- userLeaving, prev.configChangeFlags, pauseImmediately);
+
+ mService.mLifecycleManager.scheduleTransaction(prev.app.thread, prev.appToken,
+ PauseActivityItem.obtain(prev.finishing, userLeaving,
+ prev.configChangeFlags, pauseImmediately));
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
Slog.w(TAG, "Exception thrown during pause", e);
@@ -1669,12 +1684,6 @@
return true;
}
- /** Returns true if the stack is currently considered visible. */
- boolean isVisible() {
- return mWindowContainerController != null && mWindowContainerController.isVisible()
- && !mForceHidden;
- }
-
boolean isTopStackOnDisplay() {
return getDisplay().isTopStack(this);
}
@@ -2055,7 +2064,8 @@
if (r.app != null && r.app.thread != null) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Scheduling invisibility: " + r);
- r.app.thread.scheduleWindowVisibility(r.appToken, false);
+ mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken,
+ WindowVisibilityItem.obtain(false /* showWindow */));
}
// Reset the flag indicating that an app can enter picture-in-picture once the
@@ -2254,7 +2264,7 @@
// Remember how we'll process this pause/resume situation, and ensure
// that the state is reset however we wind up proceeding.
- final boolean userLeaving = mStackSupervisor.mUserLeaving;
+ boolean userLeaving = mStackSupervisor.mUserLeaving;
mStackSupervisor.mUserLeaving = false;
if (!hasRunningActivity) {
@@ -2325,6 +2335,13 @@
// So, why aren't we using prev here??? See the param comment on the method. prev doesn't
// represent the last resumed activity. However, the last focus stack does if it isn't null.
final ActivityRecord lastResumed = lastFocusedStack.mResumedActivity;
+ if (userLeaving && inMultiWindowMode() && lastFocusedStack.shouldBeVisible(next)) {
+ // The user isn't leaving if this stack is the multi-window mode and the last
+ // focused stack should still be visible.
+ if(DEBUG_USER_LEAVING) Slog.i(TAG_USER_LEAVING, "Overriding userLeaving to false"
+ + " next=" + next + " lastResumed=" + lastResumed);
+ userLeaving = false;
+ }
lastResumedCanPip = lastResumed != null && lastResumed.checkEnterPictureInPictureState(
"resumeTopActivity", userLeaving /* beforeStopping */);
}
@@ -2575,13 +2592,15 @@
if (!next.finishing && N > 0) {
if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
"Delivering results to " + next + ": " + a);
- next.app.thread.scheduleSendResult(next.appToken, a);
+ mService.mLifecycleManager.scheduleTransaction(next.app.thread,
+ next.appToken, ActivityResultItem.obtain(a));
}
}
if (next.newIntents != null) {
- next.app.thread.scheduleNewIntent(
- next.newIntents, next.appToken, false /* andPause */);
+ mService.mLifecycleManager.scheduleTransaction(next.app.thread,
+ next.appToken, NewIntentItem.obtain(next.newIntents,
+ false /* andPause */));
}
// Well the app will no longer be stopped.
@@ -2598,8 +2617,9 @@
next.app.pendingUiClean = true;
next.app.forceProcessStateUpTo(mService.mTopProcessState);
next.clearOptionsLocked();
- next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
- mService.isNextTransitionForward(), resumeAnimOptions);
+ mService.mLifecycleManager.scheduleTransaction(next.app.thread, next.appToken,
+ ResumeActivityItem.obtain(next.app.repProcState,
+ mService.isNextTransitionForward()));
if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed "
+ next);
@@ -3249,7 +3269,8 @@
ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
list.add(new ResultInfo(resultWho, requestCode,
resultCode, data));
- r.app.thread.scheduleSendResult(r.appToken, list);
+ mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken,
+ ActivityResultItem.obtain(list));
return;
} catch (Exception e) {
Slog.w(TAG, "Exception thrown sending result to " + r, e);
@@ -3377,7 +3398,8 @@
}
EventLogTags.writeAmStopActivity(
r.userId, System.identityHashCode(r), r.shortComponentName);
- r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);
+ mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken,
+ StopActivityItem.obtain(r.visible, r.configChangeFlags));
if (shouldSleepOrShutDownActivities()) {
r.setSleeping(true);
}
@@ -3881,11 +3903,19 @@
try {
ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
destIntent.getComponent(), 0, srec.userId);
- int res = mService.mActivityStarter.startActivityLocked(srec.app.thread,
- destIntent, null /*ephemeralIntent*/, null, aInfo, null /*rInfo*/, null,
- null, parent.appToken, null, 0, -1, parent.launchedFromUid,
- parent.launchedFromPackage, -1, parent.launchedFromUid, 0, null,
- false, true, null, null, "navigateUpTo");
+ // TODO(b/64750076): Check if calling pid should really be -1.
+ final int res = mService.getActivityStartController()
+ .obtainStarter(destIntent, "navigateUpTo")
+ .setCaller(srec.app.thread)
+ .setActivityInfo(aInfo)
+ .setResultTo(parent.appToken)
+ .setCallingPid(-1)
+ .setCallingUid(parent.launchedFromUid)
+ .setCallingPackage(parent.launchedFromPackage)
+ .setRealCallingPid(-1)
+ .setRealCallingUid(parent.launchedFromUid)
+ .setComponentSpecified(true)
+ .execute();
foundParentInTask = res == ActivityManager.START_SUCCESS;
} catch (RemoteException e) {
foundParentInTask = false;
@@ -4009,7 +4039,7 @@
// TODO: If the callers to removeTask() changes such that we have multiple places
// where we are destroying the task, move this back into removeTask()
mStackSupervisor.removeTaskByIdLocked(task.taskId, false /* killProcess */,
- !REMOVE_FROM_RECENTS, PAUSE_IMMEDIATELY);
+ !REMOVE_FROM_RECENTS, PAUSE_IMMEDIATELY, reason);
}
// We must keep the task around until all activities are destroyed. The following
@@ -4174,8 +4204,8 @@
try {
if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + r);
- r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing,
- r.configChangeFlags);
+ mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken,
+ DestroyActivityItem.obtain(r.finishing, r.configChangeFlags));
} catch (Exception e) {
// We can just ignore exceptions here... if the process
// has crashed, our death notification will clean things
@@ -4988,13 +5018,22 @@
TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
boolean toTop) {
- final TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession,
- voiceInteractor);
+ return createTaskRecord(taskId, info, intent, voiceSession, voiceInteractor, toTop,
+ null /*activity*/, null /*source*/, null /*options*/);
+ }
+
+ TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+ boolean toTop, ActivityRecord activity, ActivityRecord source,
+ ActivityOptions options) {
+ final TaskRecord task = TaskRecord.create(
+ mService, taskId, info, intent, voiceSession, voiceInteractor);
// add the task to stack first, mTaskPositioner might need the stack association
addTask(task, toTop, "createTaskRecord");
final boolean isLockscreenShown = mService.mStackSupervisor.getKeyguardController()
.isKeyguardShowing(mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY);
- if (!mStackSupervisor.getLaunchingBoundsController().layoutTask(task, info.windowLayout)
+ if (!mStackSupervisor.getLaunchingBoundsController()
+ .layoutTask(task, info.windowLayout, activity, source, options)
&& !matchParentBounds() && task.isResizeable() && !isLockscreenShown) {
task.updateOverrideConfiguration(getOverrideBounds());
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 5525cdb..edaa511 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -114,6 +114,11 @@
import android.app.WaitResult;
import android.app.WindowConfiguration.ActivityType;
import android.app.WindowConfiguration.WindowingMode;
+import android.app.servertransaction.ActivityLifecycleItem;
+import android.app.servertransaction.ClientTransaction;
+import android.app.servertransaction.LaunchActivityItem;
+import android.app.servertransaction.PauseActivityItem;
+import android.app.servertransaction.ResumeActivityItem;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -128,7 +133,7 @@
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.hardware.display.DisplayManagerInternal;
-import android.hardware.input.InputManagerInternal;
+import android.hardware.power.V1_0.PowerHint;
import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
@@ -297,9 +302,6 @@
private LaunchingBoundsController mLaunchingBoundsController;
- /** Counter for next free stack ID to use for dynamic activity stacks. */
- private int mNextFreeStackId = 0;
-
/**
* Maps the task identifier that activities are currently being started in to the userId of the
* task. Each time a new task is created, the entry for the userId of the task is incremented
@@ -363,6 +365,9 @@
* is being brought in front of us. */
boolean mUserLeaving = false;
+ /** Set when a power hint has started, but not ended. */
+ private boolean mPowerHintSent;
+
/**
* We don't want to allow the device to go to sleep while in the process
* of launching an activity. This is primarily to allow alarm intent
@@ -977,7 +982,7 @@
}
}
// Send launch end powerhint when idle
- mService.mActivityStarter.sendPowerHintForLaunchEndIfNeeded();
+ sendPowerHintForLaunchEndIfNeeded();
return true;
}
@@ -1234,9 +1239,16 @@
ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags) {
synchronized (mService) {
- return mService.getPackageManagerInternalLocked().resolveIntent(intent, resolvedType,
- PackageManager.MATCH_INSTANT | PackageManager.MATCH_DEFAULT_ONLY | flags
- | ActivityManagerService.STOCK_PM_FLAGS, userId, true);
+ try {
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "resolveIntent");
+ return mService.getPackageManagerInternalLocked().resolveIntent(
+ intent, resolvedType, PackageManager.MATCH_INSTANT
+ | PackageManager.MATCH_DEFAULT_ONLY | flags
+ | ActivityManagerService.STOCK_PM_FLAGS, userId, true);
+
+ } finally {
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+ }
}
}
@@ -1392,15 +1404,33 @@
r.setLastReportedConfiguration(mergedConfiguration);
logIfTransactionTooLarge(r.intent, r.icicle);
- app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
+
+
+ // Create activity launch transaction.
+ final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
+ r.appToken);
+ clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
- r.persistentState, results, newIntents, !andResume,
- mService.isNextTransitionForward(), profilerInfo);
+ r.persistentState, results, newIntents, mService.isNextTransitionForward(),
+ profilerInfo));
+
+ // Set desired final state.
+ final ActivityLifecycleItem lifecycleItem;
+ if (andResume) {
+ lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
+ } else {
+ lifecycleItem = PauseActivityItem.obtain();
+ }
+ clientTransaction.setLifecycleStateRequest(lifecycleItem);
+
+ // Schedule transaction.
+ mService.mLifecycleManager.scheduleTransaction(clientTransaction);
+
if ((app.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
// This may be a heavy-weight process! Note that the package
@@ -1468,7 +1498,7 @@
// a chance to initialize itself while in the background, making the
// switch back to it faster and look better.
if (isFocusedStack(stack)) {
- mService.startSetupActivityLocked();
+ mService.getActivityStartController().startSetupActivity();
}
// Update any services we are bound to that might care about whether
@@ -1529,6 +1559,32 @@
"activity", r.intent.getComponent(), false, false, true);
}
+ void sendPowerHintForLaunchStartIfNeeded(boolean forceSend, ActivityRecord targetActivity) {
+ boolean sendHint = forceSend;
+
+ if (!sendHint) {
+ // If not forced, send power hint when the activity's process is different than the
+ // current resumed activity.
+ final ActivityRecord resumedActivity = getResumedActivityLocked();
+ sendHint = resumedActivity == null
+ || resumedActivity.app == null
+ || !resumedActivity.app.equals(targetActivity.app);
+ }
+
+ if (sendHint && mService.mLocalPowerManager != null) {
+ mService.mLocalPowerManager.powerHint(PowerHint.LAUNCH, 1);
+ mPowerHintSent = true;
+ }
+ }
+
+ void sendPowerHintForLaunchEndIfNeeded() {
+ // Trigger launch power hint if activity is launched
+ if (mPowerHintSent && mService.mLocalPowerManager != null) {
+ mService.mLocalPowerManager.powerHint(PowerHint.LAUNCH, 0);
+ mPowerHintSent = false;
+ }
+ }
+
boolean checkStartAnyActivityPermission(Intent intent, ActivityInfo aInfo,
String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, boolean ignoreTargetSecurity, ProcessRecord callerApp,
@@ -2479,14 +2535,14 @@
}
}
- private void deferUpdateBounds(int activityType) {
+ void deferUpdateBounds(int activityType) {
final ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
if (stack != null) {
stack.deferUpdateBounds();
}
}
- private void continueUpdateBounds(int activityType) {
+ void continueUpdateBounds(int activityType) {
final ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
if (stack != null) {
stack.continueUpdateBounds();
@@ -2737,7 +2793,7 @@
} else {
for (int i = tasks.size() - 1; i >= 0; i--) {
removeTaskByIdLocked(tasks.get(i).taskId, true /* killProcess */,
- REMOVE_FROM_RECENTS);
+ REMOVE_FROM_RECENTS, "remove-stack");
}
}
}
@@ -2770,8 +2826,10 @@
/**
* See {@link #removeTaskByIdLocked(int, boolean, boolean, boolean)}
*/
- boolean removeTaskByIdLocked(int taskId, boolean killProcess, boolean removeFromRecents) {
- return removeTaskByIdLocked(taskId, killProcess, removeFromRecents, !PAUSE_IMMEDIATELY);
+ boolean removeTaskByIdLocked(int taskId, boolean killProcess, boolean removeFromRecents,
+ String reason) {
+ return removeTaskByIdLocked(taskId, killProcess, removeFromRecents, !PAUSE_IMMEDIATELY,
+ reason);
}
/**
@@ -2785,10 +2843,10 @@
* @return Returns true if the given task was found and removed.
*/
boolean removeTaskByIdLocked(int taskId, boolean killProcess, boolean removeFromRecents,
- boolean pauseImmediately) {
+ boolean pauseImmediately, String reason) {
final TaskRecord tr = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
if (tr != null) {
- tr.removeTaskActivitiesLocked(pauseImmediately);
+ tr.removeTaskActivitiesLocked(pauseImmediately, reason);
cleanUpRemovedTaskLocked(tr, killProcess, removeFromRecents);
mService.mLockTaskController.clearLockedTask(tr);
if (tr.isPersistable) {
@@ -2871,16 +2929,6 @@
}
}
- int getNextStackId() {
- while (true) {
- if (getStack(mNextFreeStackId) == null) {
- break;
- }
- mNextFreeStackId++;
- }
- return mNextFreeStackId;
- }
-
/**
* Called to restore the state of the task into the stack that it's supposed to go into.
*
@@ -2922,7 +2970,12 @@
@Override
public void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed) {
- // TODO: Trim active task once b/68045330 is fixed
+ if (wasTrimmed) {
+ // Task was trimmed from the recent tasks list -- remove the active task record as well
+ // since the user won't really be able to go back to it
+ removeTaskByIdLocked(task.taskId, false /* killProcess */,
+ false /* removeFromRecents */, !PAUSE_IMMEDIATELY, "recent-task-trimmed");
+ }
task.removedFromRecents();
}
@@ -3326,7 +3379,7 @@
}
// Send launch end powerhint before going sleep
- mService.mActivityStarter.sendPowerHintForLaunchEndIfNeeded();
+ sendPowerHintForLaunchEndIfNeeded();
removeSleepTimeouts();
@@ -4299,6 +4352,10 @@
final ActivityRecord r = task.mActivities.get(i);
if (r.app != null && r.app.thread != null) {
mPipModeChangedActivities.add(r);
+ // If we are scheduling pip change, then remove this activity from multi-window
+ // change list as the processing of pip change will make sure multi-window changed
+ // message is processed in the right order relative to pip changed.
+ mMultiWindowModeChangedActivities.remove(r);
}
}
mPipModeChangedTargetStackBounds = targetStackBounds;
@@ -4460,7 +4517,7 @@
*
* @param task The task to put into resizing mode
*/
- private void setResizingDuringAnimation(TaskRecord task) {
+ void setResizingDuringAnimation(TaskRecord task) {
mResizingTasksDuringAnimation.add(task.taskId);
task.setTaskDockedResizing(true);
}
@@ -4519,8 +4576,7 @@
&& task.getRootActivity() != null) {
final ActivityRecord targetActivity = task.getTopActivity();
- mService.mActivityStarter.sendPowerHintForLaunchStartIfNeeded(true /* forceSend */,
- targetActivity);
+ sendPowerHintForLaunchStartIfNeeded(true /* forceSend */, targetActivity);
mActivityMetricsLogger.notifyActivityLaunching();
try {
mService.moveTaskToFrontLocked(task.taskId, 0, bOptions,
@@ -4537,8 +4593,9 @@
setResizingDuringAnimation(task);
}
- mService.mActivityStarter.postStartActivityProcessing(task.getTopActivity(),
- ActivityManager.START_TASK_TO_FRONT, task.getStack());
+ mService.getActivityStartController().postStartActivityProcessingForLastStarter(
+ task.getTopActivity(), ActivityManager.START_TASK_TO_FRONT,
+ task.getStack());
return ActivityManager.START_TASK_TO_FRONT;
}
callingUid = task.mCallingUid;
@@ -4546,8 +4603,9 @@
intent = task.intent;
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
userId = task.userId;
- int result = mService.startActivityInPackage(callingUid, callingPackage, intent, null,
- null, null, 0, 0, bOptions, userId, task, "startActivityFromRecents");
+ int result = mService.getActivityStartController().startActivityInPackage(callingUid,
+ callingPackage, intent, null, null, null, 0, 0, bOptions, userId, task,
+ "startActivityFromRecents");
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
setResizingDuringAnimation(task);
}
diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java
new file mode 100644
index 0000000..a97b93c
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -0,0 +1,410 @@
+/*
+ * 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.am;
+
+import static android.app.ActivityManager.START_SUCCESS;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerService.ALLOW_FULL_ONLY;
+
+import android.app.ActivityOptions;
+import android.app.IApplicationThread;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.FactoryTest;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
+import com.android.server.am.ActivityStarter.DefaultFactory;
+import com.android.server.am.ActivityStarter.Factory;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Controller for delegating activity launches.
+ *
+ * This class' main objective is to take external activity start requests and prepare them into
+ * a series of discrete activity launches that can be handled by an {@link ActivityStarter}. It is
+ * also responsible for handling logic that happens around an activity launch, but doesn't
+ * necessarily influence the activity start. Examples include power hint management, processing
+ * through the pending activity list, and recording home activity launches.
+ */
+public class ActivityStartController {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStartController" : TAG_AM;
+
+ private static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 1;
+
+ private final ActivityManagerService mService;
+ private final ActivityStackSupervisor mSupervisor;
+
+ /** Last home activity record we attempted to start. */
+ private ActivityRecord mLastHomeActivityStartRecord;
+
+ /** Temporary array to capture start activity results */
+ private ActivityRecord[] tmpOutRecord = new ActivityRecord[1];
+
+ /**The result of the last home activity we attempted to start. */
+ private int mLastHomeActivityStartResult;
+
+ /** A list of activities that are waiting to launch. */
+ private final ArrayList<ActivityStackSupervisor.PendingActivityLaunch>
+ mPendingActivityLaunches = new ArrayList<>();
+
+ private final Factory mFactory;
+
+ private final Handler mHandler;
+
+ private final class StartHandler extends Handler {
+ public StartHandler(Looper looper) {
+ super(looper, null, true);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch(msg.what) {
+ case DO_PENDING_ACTIVITY_LAUNCHES_MSG:
+ synchronized (mService) {
+ doPendingActivityLaunches(true);
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * TODO(b/64750076): Capture information necessary for dump and
+ * {@link #postStartActivityProcessingForLastStarter} rather than keeping the entire object
+ * around */
+ private ActivityStarter mLastStarter;
+
+ ActivityStartController(ActivityManagerService service) {
+ this(service, service.mStackSupervisor,
+ new DefaultFactory(service, service.mStackSupervisor,
+ new ActivityStartInterceptor(service, service.mStackSupervisor)));
+ }
+
+ @VisibleForTesting
+ ActivityStartController(ActivityManagerService service, ActivityStackSupervisor supervisor,
+ Factory factory) {
+ mService = service;
+ mSupervisor = supervisor;
+ mHandler = new StartHandler(mService.mHandlerThread.getLooper());
+ mFactory = factory;
+ mFactory.setController(this);
+ }
+
+ /**
+ * @return A starter to configure and execute starting an activity. It is valid until after
+ * {@link ActivityStarter#execute} is invoked. At that point, the starter should be
+ * considered invalid and no longer modified or used.
+ */
+ ActivityStarter obtainStarter(Intent intent, String reason) {
+ final ActivityStarter starter = mFactory.obtainStarter();
+ mLastStarter = starter;
+
+ return starter.setIntent(intent).setReason(reason);
+ }
+
+ /**
+ * TODO(b/64750076): usage of this doesn't seem right. We're making decisions based off the
+ * last starter for an arbitrary task record. Re-evaluate whether we can remove.
+ */
+ void postStartActivityProcessingForLastStarter(ActivityRecord r, int result,
+ ActivityStack targetStack) {
+ mLastStarter.postStartActivityProcessing(r, result, targetStack);
+ }
+
+ void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason) {
+ mSupervisor.moveHomeStackTaskToTop(reason);
+
+ mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)
+ .setOutActivity(tmpOutRecord)
+ .setCallingUid(0)
+ .setActivityInfo(aInfo)
+ .execute();
+ mLastHomeActivityStartRecord = tmpOutRecord[0];
+ if (mSupervisor.inResumeTopActivity) {
+ // If we are in resume section already, home activity will be initialized, but not
+ // resumed (to avoid recursive resume) and will stay that way until something pokes it
+ // again. We need to schedule another resume.
+ mSupervisor.scheduleResumeTopActivities();
+ }
+ }
+
+ /**
+ * Starts the "new version setup screen" if appropriate.
+ */
+ void startSetupActivity() {
+ // Only do this once per boot.
+ if (mService.getCheckedForSetup()) {
+ return;
+ }
+
+ // We will show this screen if the current one is a different
+ // version than the last one shown, and we are not running in
+ // low-level factory test mode.
+ final ContentResolver resolver = mService.mContext.getContentResolver();
+ if (mService.mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL &&
+ Settings.Global.getInt(resolver,
+ Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
+ mService.setCheckedForSetup(true);
+
+ // See if we should be showing the platform update setup UI.
+ final Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
+ final List<ResolveInfo> ris = mService.mContext.getPackageManager()
+ .queryIntentActivities(intent,
+ PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_META_DATA);
+ if (!ris.isEmpty()) {
+ final ResolveInfo ri = ris.get(0);
+ String vers = ri.activityInfo.metaData != null
+ ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
+ : null;
+ if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
+ vers = ri.activityInfo.applicationInfo.metaData.getString(
+ Intent.METADATA_SETUP_VERSION);
+ }
+ String lastVers = Settings.Secure.getString(
+ resolver, Settings.Secure.LAST_SETUP_SHOWN);
+ if (vers != null && !vers.equals(lastVers)) {
+ intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
+ intent.setComponent(new ComponentName(
+ ri.activityInfo.packageName, ri.activityInfo.name));
+ obtainStarter(intent, "startSetupActivity")
+ .setCallingUid(0)
+ .setActivityInfo(ri.activityInfo)
+ .execute();
+ }
+ }
+ }
+ }
+
+ final int startActivityInPackage(int uid, String callingPackage,
+ Intent intent, String resolvedType, IBinder resultTo,
+ String resultWho, int requestCode, int startFlags, Bundle bOptions, int userId,
+ TaskRecord inTask, String reason) {
+
+ userId = mService.mUserController.handleIncomingUser(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, "startActivityInPackage",
+ null);
+
+ // TODO: Switch to user app stacks here.
+ return obtainStarter(intent, reason)
+ .setCallingUid(uid)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setResultTo(resultTo)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setStartFlags(startFlags)
+ .setMayWait(bOptions, userId)
+ .setInTask(inTask)
+ .execute();
+ }
+
+ final int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents,
+ String[] resolvedTypes, IBinder resultTo, Bundle bOptions, int userId) {
+ final String reason = "startActivityInPackage";
+ userId = mService.mUserController.handleIncomingUser(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, reason, null);
+ // TODO: Switch to user app stacks here.
+ int ret = startActivities(null, uid, callingPackage, intents, resolvedTypes, resultTo,
+ bOptions, userId, reason);
+ return ret;
+ }
+
+ int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
+ Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions, int userId,
+ String reason) {
+ if (intents == null) {
+ throw new NullPointerException("intents is null");
+ }
+ if (resolvedTypes == null) {
+ throw new NullPointerException("resolvedTypes is null");
+ }
+ if (intents.length != resolvedTypes.length) {
+ throw new IllegalArgumentException("intents are length different than resolvedTypes");
+ }
+
+ final int realCallingPid = Binder.getCallingPid();
+ final int realCallingUid = Binder.getCallingUid();
+
+ int callingPid;
+ if (callingUid >= 0) {
+ callingPid = -1;
+ } else if (caller == null) {
+ callingPid = realCallingPid;
+ callingUid = realCallingUid;
+ } else {
+ callingPid = callingUid = -1;
+ }
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mService) {
+ ActivityRecord[] outActivity = new ActivityRecord[1];
+ for (int i=0; i < intents.length; i++) {
+ Intent intent = intents[i];
+ if (intent == null) {
+ continue;
+ }
+
+ // Refuse possible leaked file descriptors
+ if (intent != null && intent.hasFileDescriptors()) {
+ throw new IllegalArgumentException("File descriptors passed in Intent");
+ }
+
+ boolean componentSpecified = intent.getComponent() != null;
+
+ // Don't modify the client's object!
+ intent = new Intent(intent);
+
+ // Collect information about the target of the Intent.
+ ActivityInfo aInfo = mSupervisor.resolveActivity(intent, resolvedTypes[i], 0,
+ null, userId);
+ // TODO: New, check if this is correct
+ aInfo = mService.getActivityInfoForUser(aInfo, userId);
+
+ if (aInfo != null &&
+ (aInfo.applicationInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
+ throw new IllegalArgumentException(
+ "FLAG_CANT_SAVE_STATE not supported here");
+ }
+
+ ActivityOptions options = ActivityOptions.fromBundle(
+ i == intents.length - 1 ? bOptions : null);
+
+ final int res = obtainStarter(intent, reason)
+ .setCaller(caller)
+ .setResolvedType(resolvedTypes[i])
+ .setActivityInfo(aInfo)
+ .setResultTo(resultTo)
+ .setRequestCode(-1)
+ .setCallingPid(callingPid)
+ .setCallingUid(callingUid)
+ .setCallingPackage(callingPackage)
+ .setRealCallingPid(realCallingPid)
+ .setRealCallingUid(realCallingUid)
+ .setActivityOptions(options)
+ .setComponentSpecified(componentSpecified)
+ .setOutActivity(outActivity)
+ .execute();
+
+ if (res < 0) {
+ return res;
+ }
+
+ resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+
+ return START_SUCCESS;
+ }
+
+ void schedulePendingActivityLaunches(long delayMs) {
+ mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
+ Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
+ mHandler.sendMessageDelayed(msg, delayMs);
+ }
+
+ void doPendingActivityLaunches(boolean doResume) {
+ while (!mPendingActivityLaunches.isEmpty()) {
+ final PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
+ final boolean resume = doResume && mPendingActivityLaunches.isEmpty();
+ final ActivityStarter starter = obtainStarter(null /* intent */,
+ "pendingActivityLaunch");
+ try {
+ starter.startResolvedActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags,
+ resume, null, null, null /* outRecords */);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
+ pal.sendErrorResult(e.getMessage());
+ }
+ }
+ }
+
+ void addPendingActivityLaunch(PendingActivityLaunch launch) {
+ mPendingActivityLaunches.add(launch);
+ }
+
+ boolean clearPendingActivityLaunches(String packageName) {
+ final int pendingLaunches = mPendingActivityLaunches.size();
+
+ for (int palNdx = pendingLaunches - 1; palNdx >= 0; --palNdx) {
+ final PendingActivityLaunch pal = mPendingActivityLaunches.get(palNdx);
+ final ActivityRecord r = pal.r;
+ if (r != null && r.packageName.equals(packageName)) {
+ mPendingActivityLaunches.remove(palNdx);
+ }
+ }
+ return mPendingActivityLaunches.size() < pendingLaunches;
+ }
+
+ void dump(PrintWriter pw, String prefix, String dumpPackage) {
+ pw.print(prefix);
+ pw.print("mLastHomeActivityStartResult=");
+ pw.println(mLastHomeActivityStartResult);
+
+ if (mLastHomeActivityStartRecord != null) {
+ pw.print(prefix);
+ pw.println("mLastHomeActivityStartRecord:");
+ mLastHomeActivityStartRecord.dump(pw, prefix + " ");
+ }
+
+ final boolean dumpPackagePresent = dumpPackage != null;
+
+ if (mLastStarter != null) {
+ final boolean dump = !dumpPackagePresent
+ || mLastStarter.relatedToPackage(dumpPackage)
+ || (mLastHomeActivityStartRecord != null
+ && dumpPackage.equals(mLastHomeActivityStartRecord.packageName));
+
+ if (dump) {
+ pw.print(prefix);
+ mLastStarter.dump(pw, prefix + " ");
+
+ if (dumpPackagePresent) {
+ return;
+ }
+ }
+ }
+
+ if (dumpPackagePresent) {
+ pw.print(prefix);
+ pw.println("(nothing)");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 03162bb..10fb6e2 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -33,7 +33,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
-import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
@@ -45,7 +44,6 @@
import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
-import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
@@ -55,7 +53,6 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RESULTS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
@@ -79,7 +76,6 @@
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityOptions;
-import android.app.AppGlobals;
import android.app.IApplicationThread;
import android.app.PendingIntent;
import android.app.ProfilerInfo;
@@ -90,18 +86,17 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.AuxiliaryResolveInfo;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
-import android.hardware.power.V1_0.PowerHint;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.voice.IVoiceInteractionSession;
@@ -109,6 +104,7 @@
import android.util.EventLog;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.app.IVoiceInteractor;
import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
@@ -116,11 +112,10 @@
import java.io.PrintWriter;
import java.text.DateFormat;
-import java.util.ArrayList;
import java.util.Date;
/**
- * Controller for interpreting how and then launching activities.
+ * Controller for interpreting how and then launching an activity.
*
* This class collects all the logic for determining how an intent and flags should be turned into
* an activity and associated task and stack.
@@ -137,7 +132,7 @@
private final ActivityStackSupervisor mSupervisor;
private final ActivityStartInterceptor mInterceptor;
- final ArrayList<PendingActivityLaunch> mPendingActivityLaunches = new ArrayList<>();
+ private final ActivityStartController mController;
// Share state variable among methods when starting an activity.
private ActivityRecord mStartActivity;
@@ -171,7 +166,6 @@
private boolean mNoAnimation;
private boolean mKeepCurTransition;
private boolean mAvoidMoveToFront;
- private boolean mPowerHintSent;
// We must track when we deliver the new intent since multiple code paths invoke
// {@link #deliverNewIntent}. This is due to early returns in the code path. This flag is used
@@ -182,10 +176,6 @@
private IVoiceInteractionSession mVoiceSession;
private IVoiceInteractor mVoiceInteractor;
- // Last home activity record we attempted to start
- private final ActivityRecord[] mLastHomeActivityStartRecord = new ActivityRecord[1];
- // The result of the last home activity we attempted to start.
- private int mLastHomeActivityStartResult;
// Last activity record we attempted to start
private final ActivityRecord[] mLastStartActivityRecord = new ActivityRecord[1];
// The result of the last activity we attempted to start.
@@ -195,51 +185,158 @@
// The reason we were trying to start the last activity
private String mLastStartReason;
- private void reset() {
- mStartActivity = null;
- mIntent = null;
- mCallingUid = -1;
- mOptions = null;
+ /*
+ * Request details provided through setter methods. Should be reset after {@link #execute()}
+ * to avoid unnecessarily retaining parameters. Note that the request is ignored when
+ * {@link #startResolvedActivity} is invoked directly.
+ */
+ private Request mRequest = new Request();
- mLaunchTaskBehind = false;
- mLaunchFlags = 0;
- mLaunchMode = INVALID_LAUNCH_MODE;
+ /**
+ * An interface that to provide {@link ActivityStarter} instances to the controller. This is
+ * used by tests to inject their own starter implementations for verification purposes.
+ */
+ @VisibleForTesting
+ interface Factory {
+ /**
+ * Sets the {@link ActivityStartController} to be passed to {@link ActivityStarter}.
+ */
+ void setController(ActivityStartController controller);
- mLaunchBounds.setEmpty();
-
- mNotTop = null;
- mDoResume = false;
- mStartFlags = 0;
- mSourceRecord = null;
- mPreferredDisplayId = INVALID_DISPLAY;
-
- mInTask = null;
- mAddingToTask = false;
- mReuseTask = null;
-
- mNewTaskInfo = null;
- mNewTaskIntent = null;
- mSourceStack = null;
-
- mTargetStack = null;
- mMovedToFront = false;
- mNoAnimation = false;
- mKeepCurTransition = false;
- mAvoidMoveToFront = false;
-
- mVoiceSession = null;
- mVoiceInteractor = null;
-
- mIntentDelivered = false;
+ /**
+ * Generates an {@link ActivityStarter} that is ready to handle a new start request.
+ * @param controller The {@link ActivityStartController} which the starter who will own
+ * this instance.
+ * @return an {@link ActivityStarter}
+ */
+ ActivityStarter obtainStarter();
}
- ActivityStarter(ActivityManagerService service) {
+ /**
+ * Default implementation of {@link StarterFactory}.
+ */
+ static class DefaultFactory implements Factory {
+ private ActivityStartController mController;
+ private ActivityManagerService mService;
+ private ActivityStackSupervisor mSupervisor;
+ private ActivityStartInterceptor mInterceptor;
+
+ DefaultFactory(ActivityManagerService service,
+ ActivityStackSupervisor supervisor, ActivityStartInterceptor interceptor) {
+ mService = service;
+ mSupervisor = supervisor;
+ mInterceptor = interceptor;
+ }
+
+ @Override
+ public void setController(ActivityStartController controller) {
+ mController = controller;
+ }
+
+ @Override
+ public ActivityStarter obtainStarter() {
+ // TODO(b/64750076): Investigate recycling instances to reduce object creation overhead.
+ return new ActivityStarter(mController, mService, mSupervisor, mInterceptor);
+ }
+ }
+
+ /**
+ * Container for capturing initial start request details. This information is NOT reset until
+ * the {@link ActivityStarter} is recycled, allowing for multiple invocations with the same
+ * parameters.
+ *
+ * TODO(b/64750076): Investigate consolidating member variables of {@link ActivityStarter} with
+ * the request object. Note that some member variables are referenced in
+ * {@link #dump(PrintWriter, String)} and therefore cannot be cleared immediately after
+ * execution.
+ */
+ private static class Request {
+ private static final int DEFAULT_CALLING_UID = -1;
+ private static final int DEFAULT_CALLING_PID = 0;
+
+ IApplicationThread caller;
+ Intent intent;
+ Intent ephemeralIntent;
+ String resolvedType;
+ ActivityInfo activityInfo;
+ ResolveInfo resolveInfo;
+ IVoiceInteractionSession voiceSession;
+ IVoiceInteractor voiceInteractor;
+ IBinder resultTo;
+ String resultWho;
+ int requestCode;
+ int callingPid = DEFAULT_CALLING_UID;
+ int callingUid = DEFAULT_CALLING_PID;
+ String callingPackage;
+ int realCallingPid;
+ int realCallingUid;
+ int startFlags;
+ ActivityOptions activityOptions;
+ boolean ignoreTargetSecurity;
+ boolean componentSpecified;
+ ActivityRecord[] outActivity;
+ TaskRecord inTask;
+ String reason;
+ ProfilerInfo profilerInfo;
+ Configuration globalConfig;
+ Bundle waitOptions;
+ int userId;
+ WaitResult waitResult;
+
+ /**
+ * Indicates that we should wait for the result of the start request. This flag is set when
+ * {@link ActivityStarter#setMayWait(Bundle, int)} is called.
+ * {@see ActivityStarter#startActivityMayWait}.
+ */
+ boolean mayWait;
+ }
+
+ ActivityStarter(ActivityStartController controller, ActivityManagerService service,
+ ActivityStackSupervisor supervisor, ActivityStartInterceptor interceptor) {
+ mController = controller;
mService = service;
- mSupervisor = mService.mStackSupervisor;
- mInterceptor = new ActivityStartInterceptor(mService, mSupervisor);
+ mSupervisor = supervisor;
+ mInterceptor = interceptor;
}
- int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
+ ActivityRecord getStartActivity() {
+ return mStartActivity;
+ }
+
+ boolean relatedToPackage(String packageName) {
+ return (mLastStartActivityRecord[0] != null
+ && packageName.equals(mLastStartActivityRecord[0].packageName))
+ || (mStartActivity != null && packageName.equals(mStartActivity.packageName));
+ }
+
+ /**
+ * Starts an activity based on the request parameters provided earlier.
+ * @return The starter result.
+ */
+ int execute() {
+ // TODO(b/64750076): Look into passing request directly to these methods to allow
+ // for transactional diffs and preprocessing.
+ if (mRequest.mayWait) {
+ return startActivityMayWait(mRequest.caller, mRequest.callingUid,
+ mRequest.callingPackage, mRequest.intent, mRequest.resolvedType,
+ mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
+ mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
+ mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
+ mRequest.waitOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
+ mRequest.inTask, mRequest.reason);
+ } else {
+ return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
+ mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
+ mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
+ mRequest.resultWho, mRequest.requestCode, mRequest.callingPid,
+ mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid,
+ mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions,
+ mRequest.ignoreTargetSecurity, mRequest.componentSpecified,
+ mRequest.outActivity, mRequest.inTask, mRequest.reason);
+ }
+ }
+
+ private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
@@ -268,12 +365,11 @@
return getExternalResult(mLastStartActivityResult);
}
- public static int getExternalResult(int result) {
+ static int getExternalResult(int result) {
// Aborted results are treated as successes externally, but we must track them internally.
return result != START_ABORTED ? result : START_SUCCESS;
}
- /** DO NOT call this method directly. Use {@link #startActivityLocked} instead. */
private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
@@ -536,9 +632,8 @@
|| stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
realCallingPid, realCallingUid, "Activity start")) {
- PendingActivityLaunch pal = new PendingActivityLaunch(r,
- sourceRecord, startFlags, stack, callerApp);
- mPendingActivityLaunches.add(pal);
+ mController.addPendingActivityLaunch(new PendingActivityLaunch(r,
+ sourceRecord, startFlags, stack, callerApp));
ActivityOptions.abort(options);
return ActivityManager.START_SWITCHES_CANCELED;
}
@@ -555,10 +650,10 @@
mService.mDidAppSwitch = true;
}
- doPendingActivityLaunchesLocked(false);
+ mController.doPendingActivityLaunches(false);
- return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
- options, inTask, outActivity);
+ return startResolvedActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
+ true /* doResume */, options, inTask, outActivity);
}
/**
@@ -578,11 +673,11 @@
auxiliaryResponse.failureIntent, callingPackage, verificationBundle,
resolvedType, userId, auxiliaryResponse.packageName, auxiliaryResponse.splitName,
auxiliaryResponse.installFailureActivity, auxiliaryResponse.versionCode,
- auxiliaryResponse.token, auxiliaryResponse.needsPhaseTwo);
+ auxiliaryResponse.token, auxiliaryResponse.resolveInfo.getExtras(),
+ auxiliaryResponse.needsPhaseTwo);
}
void postStartActivityProcessing(ActivityRecord r, int result, ActivityStack targetStack) {
-
if (ActivityManager.isStartResultFatalError(result)) {
return;
}
@@ -606,21 +701,9 @@
return;
}
- if (startedActivityStack.inSplitScreenPrimaryWindowingMode()) {
- final ActivityStack homeStack = mSupervisor.mHomeStack;
- final boolean homeStackVisible = homeStack != null && homeStack.isVisible();
- if (homeStackVisible) {
- // We launch an activity while being in home stack, which means either launcher or
- // recents into docked stack. We don't want the launched activity to be alone in a
- // docked stack, so we want to immediately launch recents too.
- if (DEBUG_RECENTS) Slog.d(TAG, "Scheduling recents launch.");
- mService.mWindowManager.showRecentApps(true /* fromHome */);
- }
- return;
- }
-
- boolean clearedTask = (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
- == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK) && (mReuseTask != null);
+ final int clearTaskFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK;
+ boolean clearedTask = (mLaunchFlags & clearTaskFlags) == clearTaskFlags
+ && mReuseTask != null;
if (startedActivityStack.inPinnedWindowingMode()
&& (result == START_TASK_TO_FRONT || result == START_DELIVERED_TO_TOP
|| clearedTask)) {
@@ -632,35 +715,7 @@
}
}
- void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
- mSupervisor.moveHomeStackTaskToTop(reason);
- mLastHomeActivityStartResult = startActivityLocked(null /*caller*/, intent,
- null /*ephemeralIntent*/, null /*resolvedType*/, aInfo, null /*rInfo*/,
- null /*voiceSession*/, null /*voiceInteractor*/, null /*resultTo*/,
- null /*resultWho*/, 0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/,
- null /*callingPackage*/, 0 /*realCallingPid*/, 0 /*realCallingUid*/,
- 0 /*startFlags*/, null /*options*/, false /*ignoreTargetSecurity*/,
- false /*componentSpecified*/, mLastHomeActivityStartRecord /*outActivity*/,
- null /*inTask*/, "startHomeActivity: " + reason);
- if (mSupervisor.inResumeTopActivity) {
- // If we are in resume section already, home activity will be initialized, but not
- // resumed (to avoid recursive resume) and will stay that way until something pokes it
- // again. We need to schedule another resume.
- mSupervisor.scheduleResumeTopActivities();
- }
- }
-
- void startConfirmCredentialIntent(Intent intent, Bundle optionsBundle) {
- intent.addFlags(FLAG_ACTIVITY_NEW_TASK |
- FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
- FLAG_ACTIVITY_TASK_ON_HOME);
- ActivityOptions options = (optionsBundle != null ? new ActivityOptions(optionsBundle)
- : ActivityOptions.makeBasic());
- options.setLaunchTaskId(mSupervisor.getHomeActivity().getTask().taskId);
- mService.mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
- }
-
- final int startActivityMayWait(IApplicationThread caller, int callingUid,
+ private int startActivityMayWait(IApplicationThread caller, int callingUid,
String callingPackage, Intent intent, String resolvedType,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
@@ -804,7 +859,7 @@
}
final ActivityRecord[] outRecord = new ActivityRecord[1];
- int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
+ int res = startActivity(caller, intent, ephemeralIntent, resolvedType,
aInfo, rInfo, voiceSession, voiceInteractor,
resultTo, resultWho, requestCode, callingPid,
callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
@@ -870,115 +925,16 @@
}
}
- final int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
- Intent[] intents, String[] resolvedTypes, IBinder resultTo,
- Bundle bOptions, int userId, String reason) {
- if (intents == null) {
- throw new NullPointerException("intents is null");
- }
- if (resolvedTypes == null) {
- throw new NullPointerException("resolvedTypes is null");
- }
- if (intents.length != resolvedTypes.length) {
- throw new IllegalArgumentException("intents are length different than resolvedTypes");
- }
-
- final int realCallingPid = Binder.getCallingPid();
- final int realCallingUid = Binder.getCallingUid();
-
- int callingPid;
- if (callingUid >= 0) {
- callingPid = -1;
- } else if (caller == null) {
- callingPid = realCallingPid;
- callingUid = realCallingUid;
- } else {
- callingPid = callingUid = -1;
- }
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (mService) {
- ActivityRecord[] outActivity = new ActivityRecord[1];
- for (int i=0; i<intents.length; i++) {
- Intent intent = intents[i];
- if (intent == null) {
- continue;
- }
-
- // Refuse possible leaked file descriptors
- if (intent != null && intent.hasFileDescriptors()) {
- throw new IllegalArgumentException("File descriptors passed in Intent");
- }
-
- boolean componentSpecified = intent.getComponent() != null;
-
- // Don't modify the client's object!
- intent = new Intent(intent);
-
- // Collect information about the target of the Intent.
- ActivityInfo aInfo = mSupervisor.resolveActivity(intent, resolvedTypes[i], 0,
- null, userId);
- // TODO: New, check if this is correct
- aInfo = mService.getActivityInfoForUser(aInfo, userId);
-
- if (aInfo != null &&
- (aInfo.applicationInfo.privateFlags
- & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
- throw new IllegalArgumentException(
- "FLAG_CANT_SAVE_STATE not supported here");
- }
-
- ActivityOptions options = ActivityOptions.fromBundle(
- i == intents.length - 1 ? bOptions : null);
- int res = startActivityLocked(caller, intent, null /*ephemeralIntent*/,
- resolvedTypes[i], aInfo, null /*rInfo*/, null, null, resultTo, null, -1,
- callingPid, callingUid, callingPackage,
- realCallingPid, realCallingUid, 0,
- options, false, componentSpecified, outActivity, null, reason);
- if (res < 0) {
- return res;
- }
-
- resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
- }
- }
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
-
- return START_SUCCESS;
- }
-
- void sendPowerHintForLaunchStartIfNeeded(boolean forceSend, ActivityRecord targetActivity) {
- boolean sendHint = forceSend;
-
- if (!sendHint) {
- // If not forced, send power hint when the activity's process is different than the
- // current resumed activity.
- final ActivityRecord resumedActivity = mSupervisor.getResumedActivityLocked();
- sendHint = resumedActivity == null
- || resumedActivity.app == null
- || !resumedActivity.app.equals(targetActivity.app);
- }
-
- if (sendHint && mService.mLocalPowerManager != null) {
- mService.mLocalPowerManager.powerHint(PowerHint.LAUNCH, 1);
- mPowerHintSent = true;
- }
- }
-
- void sendPowerHintForLaunchEndIfNeeded() {
- // Trigger launch power hint if activity is launched
- if (mPowerHintSent && mService.mLocalPowerManager != null) {
- mService.mLocalPowerManager.powerHint(PowerHint.LAUNCH, 0);
- mPowerHintSent = false;
- }
- }
-
- private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
- IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
- int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
- ActivityRecord[] outActivity) {
+ /**
+ * Starts an activity based on the provided {@link ActivityRecord} and environment parameters.
+ * Note that this method is called internally as well as part of {@link #startActivity}.
+ *
+ * @return The start result.
+ */
+ int startResolvedActivity(final ActivityRecord r, ActivityRecord sourceRecord,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+ int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
+ ActivityRecord[] outActivity) {
int result = START_CANCELED;
try {
mService.mWindowManager.deferSurfaceLayout();
@@ -1076,7 +1032,7 @@
}
}
- sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, reusedActivity);
+ mSupervisor.sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, reusedActivity);
reusedActivity = setTargetStackAndMoveToFrontIfNeeded(reusedActivity);
@@ -1191,7 +1147,7 @@
EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.getTask());
mTargetStack.mLastPausedActivity = null;
- sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, mStartActivity);
+ mSupervisor.sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, mStartActivity);
mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
mOptions);
@@ -1237,8 +1193,6 @@
private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
boolean doResume, int startFlags, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
- reset();
-
mStartActivity = r;
mIntent = r.intent;
mOptions = options;
@@ -1756,7 +1710,8 @@
mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
- mVoiceInteractor, !mLaunchTaskBehind /* toTop */);
+ mVoiceInteractor, !mLaunchTaskBehind /* toTop */, mStartActivity, mSourceRecord,
+ mOptions);
addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
updateBounds(mStartActivity.getTask(), mLaunchBounds);
@@ -1944,6 +1899,7 @@
return START_SUCCESS;
}
+ @VisibleForTesting
void updateBounds(TaskRecord task, Rect bounds) {
if (bounds.isEmpty()) {
return;
@@ -1965,7 +1921,7 @@
final ActivityRecord prev = mTargetStack.getTopActivity();
final TaskRecord task = (prev != null) ? prev.getTask() : mTargetStack.createTaskRecord(
mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId), mStartActivity.info,
- mIntent, null, null, true);
+ mIntent, null, null, true, mStartActivity, mSourceRecord, mOptions);
addOrReparentStartingActivity(task, "setTaskToCurrentTopOrCreateNewTask");
mTargetStack.positionChildWindowContainerAtTop(task);
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
@@ -2007,20 +1963,6 @@
return launchFlags;
}
- final void doPendingActivityLaunchesLocked(boolean doResume) {
- while (!mPendingActivityLaunches.isEmpty()) {
- final PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
- final boolean resume = doResume && mPendingActivityLaunches.isEmpty();
- try {
- startActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags, resume, null,
- null, null /*outRecords*/);
- } catch (Exception e) {
- Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
- pal.sendErrorResult(e.getMessage());
- }
- }
- }
-
private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, int launchFlags,
ActivityOptions aOptions) {
final TaskRecord task = r.getTask();
@@ -2122,18 +2064,13 @@
return mReuseTask.getStack();
}
- final int vrDisplayId = mPreferredDisplayId == mService.mVr2dDisplayId
- ? mPreferredDisplayId : INVALID_DISPLAY;
- final ActivityStack launchStack = mSupervisor.getLaunchStack(r, aOptions, task, ON_TOP,
- vrDisplayId);
-
- if (launchStack != null) {
- return launchStack;
- }
-
if (((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0)
|| mPreferredDisplayId != DEFAULT_DISPLAY) {
- return null;
+ // We don't pass in the default display id into the get launch stack call so it can do a
+ // full resolution.
+ final int candidateDisplay =
+ mPreferredDisplayId != DEFAULT_DISPLAY ? mPreferredDisplayId : INVALID_DISPLAY;
+ return mSupervisor.getLaunchStack(r, aOptions, task, ON_TOP, candidateDisplay);
}
// Otherwise handle adjacent launch.
@@ -2165,7 +2102,7 @@
mSupervisor.getDefaultDisplay().getSplitScreenPrimaryStack();
if (dockedStack != null && !dockedStack.shouldBeVisible(r)) {
// There is a docked stack, but it isn't visible, so we can't launch into that.
- return null;
+ return mSupervisor.getLaunchStack(r, aOptions, task, ON_TOP);
} else {
return dockedStack;
}
@@ -2182,35 +2119,157 @@
(flags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0;
}
- boolean clearPendingActivityLaunchesLocked(String packageName) {
- boolean didSomething = false;
-
- for (int palNdx = mPendingActivityLaunches.size() - 1; palNdx >= 0; --palNdx) {
- PendingActivityLaunch pal = mPendingActivityLaunches.get(palNdx);
- ActivityRecord r = pal.r;
- if (r != null && r.packageName.equals(packageName)) {
- mPendingActivityLaunches.remove(palNdx);
- didSomething = true;
- }
- }
- return didSomething;
+ ActivityStarter setIntent(Intent intent) {
+ mRequest.intent = intent;
+ return this;
}
- void dump(PrintWriter pw, String prefix, String dumpPackage) {
+ ActivityStarter setReason(String reason) {
+ mRequest.reason = reason;
+ return this;
+ }
+
+ ActivityStarter setCaller(IApplicationThread caller) {
+ mRequest.caller = caller;
+ return this;
+ }
+
+ ActivityStarter setEphemeralIntent(Intent intent) {
+ mRequest.ephemeralIntent = intent;
+ return this;
+ }
+
+
+ ActivityStarter setResolvedType(String type) {
+ mRequest.resolvedType = type;
+ return this;
+ }
+
+ ActivityStarter setActivityInfo(ActivityInfo info) {
+ mRequest.activityInfo = info;
+ return this;
+ }
+
+ ActivityStarter setResolveInfo(ResolveInfo info) {
+ mRequest.resolveInfo = info;
+ return this;
+ }
+
+ ActivityStarter setVoiceSession(IVoiceInteractionSession voiceSession) {
+ mRequest.voiceSession = voiceSession;
+ return this;
+ }
+
+ ActivityStarter setVoiceInteractor(IVoiceInteractor voiceInteractor) {
+ mRequest.voiceInteractor = voiceInteractor;
+ return this;
+ }
+
+ ActivityStarter setResultTo(IBinder resultTo) {
+ mRequest.resultTo = resultTo;
+ return this;
+ }
+
+ ActivityStarter setResultWho(String resultWho) {
+ mRequest.resultWho = resultWho;
+ return this;
+ }
+
+ ActivityStarter setRequestCode(int requestCode) {
+ mRequest.requestCode = requestCode;
+ return this;
+ }
+
+ ActivityStarter setCallingPid(int pid) {
+ mRequest.callingPid = pid;
+ return this;
+ }
+
+ ActivityStarter setCallingUid(int uid) {
+ mRequest.callingUid = uid;
+ return this;
+ }
+
+ ActivityStarter setCallingPackage(String callingPackage) {
+ mRequest.callingPackage = callingPackage;
+ return this;
+ }
+
+ ActivityStarter setRealCallingPid(int pid) {
+ mRequest.realCallingPid = pid;
+ return this;
+ }
+
+ ActivityStarter setRealCallingUid(int uid) {
+ mRequest.realCallingUid = uid;
+ return this;
+ }
+
+ ActivityStarter setStartFlags(int startFlags) {
+ mRequest.startFlags = startFlags;
+ return this;
+ }
+
+ ActivityStarter setActivityOptions(ActivityOptions options) {
+ mRequest.activityOptions = options;
+ return this;
+ }
+
+ ActivityStarter setIgnoreTargetSecurity(boolean ignoreTargetSecurity) {
+ mRequest.ignoreTargetSecurity = ignoreTargetSecurity;
+ return this;
+ }
+
+ ActivityStarter setComponentSpecified(boolean componentSpecified) {
+ mRequest.componentSpecified = componentSpecified;
+ return this;
+ }
+
+ ActivityStarter setOutActivity(ActivityRecord[] outActivity) {
+ mRequest.outActivity = outActivity;
+ return this;
+ }
+
+ ActivityStarter setInTask(TaskRecord inTask) {
+ mRequest.inTask = inTask;
+ return this;
+ }
+
+ ActivityStarter setWaitResult(WaitResult result) {
+ mRequest.waitResult = result;
+ return this;
+ }
+
+ ActivityStarter setProfilerInfo(ProfilerInfo info) {
+ mRequest.profilerInfo = info;
+ return this;
+ }
+
+ ActivityStarter setGlobalConfiguration(Configuration config) {
+ mRequest.globalConfig = config;
+ return this;
+ }
+
+ ActivityStarter setWaitOptions(Bundle options) {
+ mRequest.waitOptions = options;
+ return this;
+ }
+
+ ActivityStarter setUserId(int userId) {
+ mRequest.userId = userId;
+ return this;
+ }
+
+ ActivityStarter setMayWait(Bundle options, int userId) {
+ mRequest.mayWait = true;
+ mRequest.waitOptions = options;
+ mRequest.userId = userId;
+
+ return this;
+ }
+
+ void dump(PrintWriter pw, String prefix) {
prefix = prefix + " ";
-
- if (dumpPackage != null) {
- if ((mLastStartActivityRecord[0] == null ||
- !dumpPackage.equals(mLastHomeActivityStartRecord[0].packageName)) &&
- (mLastHomeActivityStartRecord[0] == null ||
- !dumpPackage.equals(mLastHomeActivityStartRecord[0].packageName)) &&
- (mStartActivity == null || !dumpPackage.equals(mStartActivity.packageName))) {
- pw.print(prefix);
- pw.println("(nothing)");
- return;
- }
- }
-
pw.print(prefix);
pw.print("mCurrentUser=");
pw.println(mSupervisor.mCurrentUser);
@@ -2229,15 +2288,6 @@
pw.println("mLastStartActivityRecord:");
r.dump(pw, prefix + " ");
}
- pw.print(prefix);
- pw.print("mLastHomeActivityStartResult=");
- pw.println(mLastHomeActivityStartResult);
- r = mLastHomeActivityStartRecord[0];
- if (r != null) {
- pw.print(prefix);
- pw.println("mLastHomeActivityStartRecord:");
- r.dump(pw, prefix + " ");
- }
if (mStartActivity != null) {
pw.print(prefix);
pw.println("mStartActivity:");
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index fe38097..d0bc33a 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -407,10 +407,10 @@
// recents entry. Let's see if we have a safe-to-restart intent.
final Set<String> cats = task.intent.getCategories();
if (cats != null && cats.contains(Intent.CATEGORY_LAUNCHER)) {
- mService.startActivityInPackage(task.mCallingUid,
- task.mCallingPackage, task.intent, null, null, null, 0, 0,
- ActivityOptions.makeBasic().toBundle(), task.userId, null,
- "AppErrors");
+ mService.getActivityStartController().startActivityInPackage(
+ task.mCallingUid, task.mCallingPackage, task.intent, null, null,
+ null, 0, 0, ActivityOptions.makeBasic().toBundle(), task.userId,
+ null, "AppErrors");
}
}
}
diff --git a/services/core/java/com/android/server/am/AppTaskImpl.java b/services/core/java/com/android/server/am/AppTaskImpl.java
index 17626ea..f821f6b 100644
--- a/services/core/java/com/android/server/am/AppTaskImpl.java
+++ b/services/core/java/com/android/server/am/AppTaskImpl.java
@@ -61,7 +61,7 @@
try {
// We remove the task from recents to preserve backwards
if (!mService.mStackSupervisor.removeTaskByIdLocked(mTaskId, false,
- REMOVE_FROM_RECENTS)) {
+ REMOVE_FROM_RECENTS, "finish-and-remove-task")) {
throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
}
} finally {
@@ -122,9 +122,14 @@
throw new IllegalArgumentException("Bad app thread " + appThread);
}
}
- return mService.mActivityStarter.startActivityMayWait(appThread, -1, callingPackage,
- intent, resolvedType, null, null, null, null, 0, 0, null, null,
- null, bOptions, false, callingUser, tr, "AppTaskImpl");
+
+ return mService.getActivityStartController().obtainStarter(intent, "AppTaskImpl")
+ .setCaller(appThread)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setMayWait(bOptions, callingUser)
+ .setInTask(tr)
+ .execute();
}
@Override
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index a035bd0..87690d1 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -932,11 +932,10 @@
enforceCallingPermission();
synchronized (mStats) {
mStats.noteDeviceIdleModeLocked(mode, activeReason, activeUid);
- StatsLog.write(StatsLog.DEVICE_IDLE_MODE_STATE_CHANGED, mode);
}
}
- public void notePackageInstalled(String pkgName, int versionCode) {
+ public void notePackageInstalled(String pkgName, long versionCode) {
enforceCallingPermission();
synchronized (mStats) {
mStats.notePackageInstalledLocked(pkgName, versionCode);
diff --git a/services/core/java/com/android/server/am/ClientLifecycleManager.java b/services/core/java/com/android/server/am/ClientLifecycleManager.java
new file mode 100644
index 0000000..cc70f18
--- /dev/null
+++ b/services/core/java/com/android/server/am/ClientLifecycleManager.java
@@ -0,0 +1,121 @@
+/*
+ * 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.am;
+
+import android.annotation.NonNull;
+import android.app.IApplicationThread;
+import android.app.servertransaction.ClientTransaction;
+import android.app.servertransaction.ClientTransactionItem;
+import android.app.servertransaction.ActivityLifecycleItem;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+/**
+ * Class that is able to combine multiple client lifecycle transition requests and/or callbacks,
+ * and execute them as a single transaction.
+ *
+ * @see ClientTransaction
+ */
+class ClientLifecycleManager {
+ // TODO(lifecycler): Implement building transactions or global transaction.
+ // TODO(lifecycler): Use object pools for transactions and transaction items.
+
+ /**
+ * Schedule a transaction, which may consist of multiple callbacks and a lifecycle request.
+ * @param transaction A sequence of client transaction items.
+ * @throws RemoteException
+ *
+ * @see ClientTransaction
+ */
+ void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
+ transaction.schedule();
+ transaction.recycle();
+ }
+
+ /**
+ * Schedule a single lifecycle request or callback to client activity.
+ * @param client Target client.
+ * @param activityToken Target activity token.
+ * @param stateRequest A request to move target activity to a desired lifecycle state.
+ * @throws RemoteException
+ *
+ * @see ClientTransactionItem
+ */
+ void scheduleTransaction(@NonNull IApplicationThread client, @NonNull IBinder activityToken,
+ @NonNull ActivityLifecycleItem stateRequest) throws RemoteException {
+ final ClientTransaction clientTransaction = transactionWithState(client, activityToken,
+ stateRequest);
+ scheduleTransaction(clientTransaction);
+ }
+
+ /**
+ * Schedule a single callback delivery to client activity.
+ * @param client Target client.
+ * @param activityToken Target activity token.
+ * @param callback A request to deliver a callback.
+ * @throws RemoteException
+ *
+ * @see ClientTransactionItem
+ */
+ void scheduleTransaction(@NonNull IApplicationThread client, @NonNull IBinder activityToken,
+ @NonNull ClientTransactionItem callback) throws RemoteException {
+ final ClientTransaction clientTransaction = transactionWithCallback(client, activityToken,
+ callback);
+ scheduleTransaction(clientTransaction);
+ }
+
+ /**
+ * Schedule a single callback delivery to client application.
+ * @param client Target client.
+ * @param callback A request to deliver a callback.
+ * @throws RemoteException
+ *
+ * @see ClientTransactionItem
+ */
+ void scheduleTransaction(@NonNull IApplicationThread client,
+ @NonNull ClientTransactionItem callback) throws RemoteException {
+ final ClientTransaction clientTransaction = transactionWithCallback(client,
+ null /* activityToken */, callback);
+ scheduleTransaction(clientTransaction);
+ }
+
+ /**
+ * @return A new instance of {@link ClientTransaction} with a single lifecycle state request.
+ *
+ * @see ClientTransaction
+ * @see ClientTransactionItem
+ */
+ private static ClientTransaction transactionWithState(@NonNull IApplicationThread client,
+ @NonNull IBinder activityToken, @NonNull ActivityLifecycleItem stateRequest) {
+ final ClientTransaction clientTransaction = ClientTransaction.obtain(client, activityToken);
+ clientTransaction.setLifecycleStateRequest(stateRequest);
+ return clientTransaction;
+ }
+
+ /**
+ * @return A new instance of {@link ClientTransaction} with a single callback invocation.
+ *
+ * @see ClientTransaction
+ * @see ClientTransactionItem
+ */
+ private static ClientTransaction transactionWithCallback(@NonNull IApplicationThread client,
+ IBinder activityToken, @NonNull ClientTransactionItem callback) {
+ final ClientTransaction clientTransaction = ClientTransaction.obtain(client, activityToken);
+ clientTransaction.addCallback(callback);
+ return clientTransaction;
+ }
+}
diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
index 82019fd..65c4a42 100644
--- a/services/core/java/com/android/server/am/CompatModePackages.java
+++ b/services/core/java/com/android/server/am/CompatModePackages.java
@@ -58,10 +58,6 @@
public static final int COMPAT_FLAG_DONT_ASK = 1<<0;
// Compatibility state: compatibility mode is enabled.
public static final int COMPAT_FLAG_ENABLED = 1<<1;
- // Unsupported zoom state: don't warn the user about unsupported zoom mode.
- public static final int UNSUPPORTED_ZOOM_FLAG_DONT_NOTIFY = 1<<2;
- // Unsupported compile SDK state: don't warn the user about unsupported compile SDK.
- public static final int UNSUPPORTED_COMPILE_SDK_FLAG_DONT_NOTIFY = 1<<3;
private final HashMap<String, Integer> mPackages = new HashMap<String, Integer>();
@@ -235,14 +231,6 @@
return (getPackageFlags(packageName)&COMPAT_FLAG_DONT_ASK) == 0;
}
- public boolean getPackageNotifyUnsupportedZoomLocked(String packageName) {
- return (getPackageFlags(packageName)&UNSUPPORTED_ZOOM_FLAG_DONT_NOTIFY) == 0;
- }
-
- public boolean getPackageNotifyUnsupportedCompileSdkLocked(String packageName) {
- return (getPackageFlags(packageName)&UNSUPPORTED_COMPILE_SDK_FLAG_DONT_NOTIFY) == 0;
- }
-
public void setFrontActivityAskCompatModeLocked(boolean ask) {
ActivityRecord r = mService.getFocusedStack().topRunningActivityLocked();
if (r != null) {
@@ -254,14 +242,6 @@
setPackageFlagLocked(packageName, COMPAT_FLAG_DONT_ASK, ask);
}
- public void setPackageNotifyUnsupportedZoomLocked(String packageName, boolean notify) {
- setPackageFlagLocked(packageName, UNSUPPORTED_ZOOM_FLAG_DONT_NOTIFY, notify);
- }
-
- public void setPackageNotifyUnsupportedCompileSdkLocked(String packageName, boolean notify) {
- setPackageFlagLocked(packageName, UNSUPPORTED_COMPILE_SDK_FLAG_DONT_NOTIFY, notify);
- }
-
private void setPackageFlagLocked(String packageName, int flag, boolean set) {
final int curFlags = getPackageFlags(packageName);
final int newFlags = set ? (curFlags & ~flag) : (curFlags | flag);
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index b2d3137..a131db5 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -38,7 +38,7 @@
# The Activity Manager failed to pause the given activity.
30012 am_failed_to_pause (User|1|5),(Token|1|5),(Wanting to pause|3),(Currently pausing|3)
# Attempting to pause the current activity
-30013 am_pause_activity (User|1|5),(Token|1|5),(Component Name|3)
+30013 am_pause_activity (User|1|5),(Token|1|5),(Component Name|3),(User Leaving|3)
# Application process has been started
30014 am_proc_start (User|1|5),(PID|1|5),(UID|1|5),(Process Name|3),(Type|3),(Component|3)
# An application process has been marked as bad
diff --git a/services/core/java/com/android/server/am/LaunchingBoundsController.java b/services/core/java/com/android/server/am/LaunchingBoundsController.java
index c762f7f..5aa7f58 100644
--- a/services/core/java/com/android/server/am/LaunchingBoundsController.java
+++ b/services/core/java/com/android/server/am/LaunchingBoundsController.java
@@ -101,8 +101,12 @@
* @return {@code true} if bounds were set on the task. {@code false} otherwise.
*/
boolean layoutTask(TaskRecord task, WindowLayout layout) {
- calculateBounds(task, layout, null /*activity*/, null /*source*/, null /*options*/,
- mTmpRect);
+ return layoutTask(task, layout, null /*activity*/, null /*source*/, null /*options*/);
+ }
+
+ boolean layoutTask(TaskRecord task, WindowLayout layout, ActivityRecord activity,
+ ActivityRecord source, ActivityOptions options) {
+ calculateBounds(task, layout, activity, source, options, mTmpRect);
if (mTmpRect.isEmpty()) {
return false;
diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java
index e87b4e6..ba3e25a 100644
--- a/services/core/java/com/android/server/am/LockTaskController.java
+++ b/services/core/java/com/android/server/am/LockTaskController.java
@@ -22,8 +22,10 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Context.DEVICE_POLICY_SERVICE;
import static android.content.Context.STATUS_BAR_SERVICE;
+import static android.content.Intent.ACTION_CALL_EMERGENCY;
import static android.os.UserHandle.USER_ALL;
import static android.os.UserHandle.USER_CURRENT;
+import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
@@ -45,6 +47,7 @@
import android.app.admin.IDevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.os.Binder;
import android.os.Debug;
import android.os.Handler;
@@ -52,9 +55,11 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
+import android.telecom.TelecomManager;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
@@ -133,6 +138,8 @@
WindowManagerService mWindowManager;
@VisibleForTesting
LockPatternUtils mLockPatternUtils;
+ @VisibleForTesting
+ TelecomManager mTelecomManager;
/**
* Helper that is responsible for showing the right toast when a disallowed activity operation
@@ -165,7 +172,7 @@
/**
* Features that are allowed by DPC to show during LockTask mode.
*/
- private final SparseArray<Integer> mLockTaskFeatures = new SparseArray<>();
+ private final SparseIntArray mLockTaskFeatures = new SparseIntArray();
/**
* Store the current lock task mode. Possible values:
@@ -250,7 +257,24 @@
}
/**
- * @return whether the requested task is allowed to be launched.
+ * @return whether the requested task is allowed to be locked (either whitelisted, or declares
+ * lockTaskMode="always" in the manifest).
+ */
+ boolean isTaskWhitelisted(TaskRecord task) {
+ switch(task.mLockTaskAuth) {
+ case LOCK_TASK_AUTH_WHITELISTED:
+ case LOCK_TASK_AUTH_LAUNCHABLE:
+ case LOCK_TASK_AUTH_LAUNCHABLE_PRIV:
+ return true;
+ case LOCK_TASK_AUTH_PINNABLE:
+ case LOCK_TASK_AUTH_DONT_LOCK:
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * @return whether the requested task is disallowed to be launched.
*/
boolean isLockTaskModeViolation(TaskRecord task) {
return isLockTaskModeViolation(task, false);
@@ -258,7 +282,7 @@
/**
* @param isNewClearTask whether the task would be cleared as part of the operation.
- * @return whether the requested task is allowed to be launched.
+ * @return whether the requested task is disallowed to be launched.
*/
boolean isLockTaskModeViolation(TaskRecord task, boolean isNewClearTask) {
if (isLockTaskModeViolationInternal(task, isNewClearTask)) {
@@ -275,21 +299,54 @@
// If the task is already at the top and won't be cleared, then allow the operation
return false;
}
- final int lockTaskAuth = task.mLockTaskAuth;
- switch (lockTaskAuth) {
- case LOCK_TASK_AUTH_DONT_LOCK:
- return !mLockTaskModeTasks.isEmpty();
- case LOCK_TASK_AUTH_LAUNCHABLE_PRIV:
- case LOCK_TASK_AUTH_LAUNCHABLE:
- case LOCK_TASK_AUTH_WHITELISTED:
- return false;
- case LOCK_TASK_AUTH_PINNABLE:
- // Pinnable tasks can't be launched on top of locktask tasks.
- return !mLockTaskModeTasks.isEmpty();
- default:
- Slog.w(TAG, "isLockTaskModeViolation: invalid lockTaskAuth value=" + lockTaskAuth);
- return true;
+
+ // Allow recents activity if enabled by policy
+ if (task.isActivityTypeRecents() && isRecentsAllowed(task.userId)) {
+ return false;
}
+
+ // Allow emergency calling when the device is protected by a locked keyguard
+ if (isKeyguardAllowed(task.userId) && isEmergencyCallTask(task)) {
+ return false;
+ }
+
+ return !(isTaskWhitelisted(task) || mLockTaskModeTasks.isEmpty());
+ }
+
+ private boolean isRecentsAllowed(int userId) {
+ return (getLockTaskFeaturesForUser(userId)
+ & DevicePolicyManager.LOCK_TASK_FEATURE_RECENTS) != 0;
+ }
+
+ private boolean isKeyguardAllowed(int userId) {
+ return (getLockTaskFeaturesForUser(userId)
+ & DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD) != 0;
+ }
+
+ private boolean isEmergencyCallTask(TaskRecord task) {
+ final Intent intent = task.intent;
+ if (intent == null) {
+ return false;
+ }
+
+ // 1. The emergency keypad activity launched on top of the keyguard
+ if (EMERGENCY_DIALER_COMPONENT.equals(intent.getComponent())) {
+ return true;
+ }
+
+ // 2. The intent sent by the keypad, which is handled by Telephony
+ if (ACTION_CALL_EMERGENCY.equals(intent.getAction())) {
+ return true;
+ }
+
+ // 3. Telephony then starts the default package for making the call
+ final TelecomManager tm = getTelecomManager();
+ final String dialerPackage = tm != null ? tm.getSystemDialerPackage() : null;
+ if (dialerPackage != null && dialerPackage.equals(intent.getComponent().getPackageName())) {
+ return true;
+ }
+
+ return false;
}
/**
@@ -491,6 +548,7 @@
}
if (mLockTaskModeTasks.isEmpty()) {
+ mSupervisor.mRecentTasks.onLockTaskModeStateChanged(lockTaskModeState, task.userId);
// Start lock task on the handler thread
mHandler.post(() -> performStartLockTask(
task.intent.getComponent().getPackageName(),
@@ -671,11 +729,10 @@
mWindowManager.reenableKeyguard(mToken);
} else if (lockTaskModeState == LOCK_TASK_MODE_LOCKED) {
- int lockTaskFeatures = getLockTaskFeaturesForUser(userId);
- if ((DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD & lockTaskFeatures) == 0) {
- mWindowManager.disableKeyguard(mToken, LOCK_TASK_TAG);
- } else {
+ if (isKeyguardAllowed(userId)) {
mWindowManager.reenableKeyguard(mToken);
+ } else {
+ mWindowManager.disableKeyguard(mToken, LOCK_TASK_TAG);
}
} else { // lockTaskModeState == LOCK_TASK_MODE_PINNED
@@ -769,6 +826,15 @@
return mLockPatternUtils;
}
+ @Nullable
+ private TelecomManager getTelecomManager() {
+ if (mTelecomManager == null) {
+ // We don't preserve the TelecomManager object to save memory
+ return mContext.getSystemService(TelecomManager.class);
+ }
+ return mTelecomManager;
+ }
+
// Should only be called on the handler thread
@NonNull
private LockTaskNotify getLockTaskNotify() {
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 7930f53..c26e770 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -332,12 +332,14 @@
}
allIntents[allIntents.length-1] = finalIntent;
allResolvedTypes[allResolvedTypes.length-1] = resolvedType;
- owner.startActivitiesInPackage(uid, key.packageName, allIntents,
- allResolvedTypes, resultTo, options, userId);
+ owner.getActivityStartController().startActivitiesInPackage(uid,
+ key.packageName, allIntents, allResolvedTypes, resultTo,
+ options, userId);
} else {
- owner.startActivityInPackage(uid, key.packageName, finalIntent,
- resolvedType, resultTo, resultWho, requestCode, 0,
- options, userId, null, "PendingIntentRecord");
+ owner.getActivityStartController().startActivityInPackage(uid,
+ key.packageName, finalIntent, resolvedType, resultTo,
+ resultWho, requestCode, 0, options, userId, null,
+ "PendingIntentRecord");
}
} catch (RuntimeException e) {
Slog.w(TAG, "Unable to send startActivity intent", e);
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 1a19601..6fb3dbb 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -40,7 +40,7 @@
/**
* Activity manager code dealing with processes.
*/
-final class ProcessList {
+public final class ProcessList {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessList" : TAG_AM;
// The minimum time we allow between crashes, for us to consider this
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 9d3c2ae..71d6604 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -730,7 +730,7 @@
/*
* Return true if package has been added false if not
*/
- public boolean addPackage(String pkg, int versionCode, ProcessStatsService tracker) {
+ public boolean addPackage(String pkg, long versionCode, ProcessStatsService tracker) {
if (!pkgList.containsKey(pkg)) {
ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
versionCode);
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index effb86c..5f9d616 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -27,6 +27,7 @@
import android.service.procstats.ProcessStatsServiceDumpProto;
import android.util.ArrayMap;
import android.util.AtomicFile;
+import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -120,12 +121,12 @@
}
public ProcessState getProcessStateLocked(String packageName,
- int uid, int versionCode, String processName) {
+ int uid, long versionCode, String processName) {
return mProcessStats.getProcessStateLocked(packageName, uid, versionCode, processName);
}
public ServiceState getServiceStateLocked(String packageName, int uid,
- int versionCode, String processName, String className) {
+ long versionCode, String processName, String className) {
return mProcessStats.getServiceStateLocked(packageName, uid, versionCode, processName,
className);
}
@@ -150,12 +151,13 @@
}
mProcessStats.mMemFactor = memFactor;
mProcessStats.mStartTime = now;
- final ArrayMap<String, SparseArray<SparseArray<ProcessStats.PackageState>>> pmap
+ final ArrayMap<String, SparseArray<LongSparseArray<ProcessStats.PackageState>>> pmap
= mProcessStats.mPackages.getMap();
for (int ipkg=pmap.size()-1; ipkg>=0; ipkg--) {
- final SparseArray<SparseArray<ProcessStats.PackageState>> uids = pmap.valueAt(ipkg);
+ final SparseArray<LongSparseArray<ProcessStats.PackageState>> uids =
+ pmap.valueAt(ipkg);
for (int iuid=uids.size()-1; iuid>=0; iuid--) {
- final SparseArray<ProcessStats.PackageState> vers = uids.valueAt(iuid);
+ final LongSparseArray<ProcessStats.PackageState> vers = uids.valueAt(iuid);
for (int iver=vers.size()-1; iver>=0; iver--) {
final ProcessStats.PackageState pkg = vers.valueAt(iver);
final ArrayMap<String, ServiceState> services = pkg.mServices;
@@ -308,17 +310,17 @@
Slog.w(TAG, " Uid " + uids.keyAt(iu) + ": " + uids.valueAt(iu));
}
}
- ArrayMap<String, SparseArray<SparseArray<ProcessStats.PackageState>>> pkgMap
+ ArrayMap<String, SparseArray<LongSparseArray<ProcessStats.PackageState>>> pkgMap
= stats.mPackages.getMap();
final int NPKG = pkgMap.size();
for (int ip=0; ip<NPKG; ip++) {
Slog.w(TAG, "Package: " + pkgMap.keyAt(ip));
- SparseArray<SparseArray<ProcessStats.PackageState>> uids
+ SparseArray<LongSparseArray<ProcessStats.PackageState>> uids
= pkgMap.valueAt(ip);
final int NUID = uids.size();
for (int iu=0; iu<NUID; iu++) {
Slog.w(TAG, " Uid: " + uids.keyAt(iu));
- SparseArray<ProcessStats.PackageState> vers = uids.valueAt(iu);
+ LongSparseArray<ProcessStats.PackageState> vers = uids.valueAt(iu);
final int NVERS = vers.size();
for (int iv=0; iv<NVERS; iv++) {
Slog.w(TAG, " Vers: " + vers.keyAt(iv));
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index 6e6d7e9..abb296e 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -80,6 +80,20 @@
/**
* Class for managing the recent tasks list. The list is ordered by most recent (index 0) to the
* least recent.
+ *
+ * The trimming logic can be boiled down to the following. For recent task list with a number of
+ * tasks, the visible tasks are an interleaving subset of tasks that would normally be presented to
+ * the user. Non-visible tasks are not considered for trimming. Of the visible tasks, only a
+ * sub-range are presented to the user, based on the device type, last task active time, or other
+ * task state. Tasks that are not in the visible range and are not returnable from the SystemUI
+ * (considering the back stack) are considered trimmable. If the device does not support recent
+ * tasks, then trimming is completely disabled.
+ *
+ * eg.
+ * L = [TTTTTTTTTTTTTTTTTTTTTTTTTT] // list of tasks
+ * [VVV VV VVVV V V V ] // Visible tasks
+ * [RRR RR XXXX X X X ] // Visible range tasks, eg. if the device only shows 5 tasks,
+ * // 'X' tasks are trimmed.
*/
class RecentTasks {
private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentTasks" : TAG_AM;
@@ -488,6 +502,18 @@
}
}
+ void onLockTaskModeStateChanged(int lockTaskModeState, int userId) {
+ if (lockTaskModeState != ActivityManager.LOCK_TASK_MODE_LOCKED) {
+ return;
+ }
+ for (int i = mTasks.size() - 1; i >= 0; --i) {
+ final TaskRecord tr = mTasks.get(i);
+ if (tr.userId == userId && !mService.mLockTaskController.isTaskWhitelisted(tr)) {
+ remove(tr);
+ }
+ }
+ }
+
void removeTasksByPackageName(String packageName, int userId) {
for (int i = mTasks.size() - 1; i >= 0; --i) {
final TaskRecord tr = mTasks.get(i);
@@ -496,7 +522,8 @@
if (tr.userId != userId) return;
if (!taskPackageName.equals(packageName)) return;
- mService.mStackSupervisor.removeTaskByIdLocked(tr.taskId, true, REMOVE_FROM_RECENTS);
+ mService.mStackSupervisor.removeTaskByIdLocked(tr.taskId, true, REMOVE_FROM_RECENTS,
+ "remove-package-task");
}
}
@@ -513,7 +540,7 @@
&& (filterByClasses == null || filterByClasses.contains(cn.getClassName()));
if (sameComponent) {
mService.mStackSupervisor.removeTaskByIdLocked(tr.taskId, false,
- REMOVE_FROM_RECENTS);
+ REMOVE_FROM_RECENTS, "disabled-package");
}
}
}
@@ -1001,12 +1028,13 @@
continue;
} else {
numVisibleTasks++;
- if (isInVisibleRange(task, numVisibleTasks)) {
+ if (isInVisibleRange(task, numVisibleTasks) || !isTrimmable(task)) {
// Keep visible tasks in range
i++;
continue;
} else {
- // Fall through to trim visible tasks that are no longer in range
+ // Fall through to trim visible tasks that are no longer in range and
+ // trimmable
if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG,
"Trimming out-of-range visible task=" + task);
}
@@ -1122,6 +1150,28 @@
}
/**
+ * @return whether the given task can be trimmed even if it is outside the visible range.
+ */
+ protected boolean isTrimmable(TaskRecord task) {
+ final ActivityStack stack = task.getStack();
+ final ActivityStack homeStack = mService.mStackSupervisor.mHomeStack;
+
+ // No stack for task, just trim it
+ if (stack == null) {
+ return true;
+ }
+
+ // Ignore tasks from different displays
+ if (stack.getDisplay() != homeStack.getDisplay()) {
+ return false;
+ }
+
+ // Trim tasks that are in stacks that are behind the home stack
+ final ActivityDisplay display = stack.getDisplay();
+ return display.getIndexOf(stack) < display.getIndexOf(homeStack);
+ }
+
+ /**
* If needed, remove oldest existing entries in recents that are for the same kind
* of task as the given one.
*/
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 365990f..48737a5 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -193,6 +193,11 @@
// Do not move the stack as a part of reparenting
static final int REPARENT_LEAVE_STACK_IN_PLACE = 2;
+ /**
+ * The factory used to create {@link TaskRecord}. This allows OEM subclass {@link TaskRecord}.
+ */
+ private static TaskRecordFactory sTaskRecordFactory;
+
final int taskId; // Unique identifier for this task.
String affinity; // The affinity name for this task, or null; may change identity.
String rootAffinity; // Initial base affinity, or null; does not change from initial root.
@@ -312,6 +317,10 @@
private TaskWindowContainerController mWindowContainerController;
+ /**
+ * Don't use constructor directly. Use {@link #create(ActivityManagerService, int, ActivityInfo,
+ * Intent, TaskDescription)} instead.
+ */
TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
mService = service;
@@ -331,6 +340,10 @@
mService.mTaskChangeNotificationController.notifyTaskCreated(_taskId, realActivity);
}
+ /**
+ * Don't use constructor directly. Use {@link #create(ActivityManagerService, int, ActivityInfo,
+ * Intent, IVoiceInteractionSession, IVoiceInteractor)} instead.
+ */
TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
TaskDescription _taskDescription) {
mService = service;
@@ -357,7 +370,10 @@
mService.mTaskChangeNotificationController.notifyTaskCreated(_taskId, realActivity);
}
- private TaskRecord(ActivityManagerService service, int _taskId, Intent _intent,
+ /**
+ * Don't use constructor directly. This is only used by XML parser.
+ */
+ TaskRecord(ActivityManagerService service, int _taskId, Intent _intent,
Intent _affinityIntent, String _affinity, String _rootAffinity,
ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId,
@@ -1311,7 +1327,8 @@
* Completely remove all activities associated with an existing
* task starting at a specified index.
*/
- final void performClearTaskAtIndexLocked(int activityNdx, boolean pauseImmediately) {
+ final void performClearTaskAtIndexLocked(int activityNdx, boolean pauseImmediately,
+ String reason) {
int numActivities = mActivities.size();
for ( ; activityNdx < numActivities; ++activityNdx) {
final ActivityRecord r = mActivities.get(activityNdx);
@@ -1325,7 +1342,7 @@
--activityNdx;
--numActivities;
} else if (mStack.finishActivityLocked(r, Activity.RESULT_CANCELED, null,
- "clear-task-index", false, pauseImmediately)) {
+ reason, false, pauseImmediately)) {
--activityNdx;
--numActivities;
}
@@ -1337,7 +1354,7 @@
*/
void performClearTaskLocked() {
mReuseTask = true;
- performClearTaskAtIndexLocked(0, !PAUSE_IMMEDIATELY);
+ performClearTaskAtIndexLocked(0, !PAUSE_IMMEDIATELY, "clear-task-all");
mReuseTask = false;
}
@@ -1408,9 +1425,9 @@
return null;
}
- void removeTaskActivitiesLocked(boolean pauseImmediately) {
+ void removeTaskActivitiesLocked(boolean pauseImmediately, String reason) {
// Just remove the entire task.
- performClearTaskAtIndexLocked(0, pauseImmediately);
+ performClearTaskAtIndexLocked(0, pauseImmediately, reason);
}
String lockTaskAuthToString() {
@@ -1631,278 +1648,6 @@
updateTaskDescription();
}
- void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
- if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
-
- out.attribute(null, ATTR_TASKID, String.valueOf(taskId));
- if (realActivity != null) {
- out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
- }
- out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended));
- if (origActivity != null) {
- out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
- }
- // Write affinity, and root affinity if it is different from affinity.
- // We use the special string "@" for a null root affinity, so we can identify
- // later whether we were given a root affinity or should just make it the
- // same as the affinity.
- if (affinity != null) {
- out.attribute(null, ATTR_AFFINITY, affinity);
- if (!affinity.equals(rootAffinity)) {
- out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
- }
- } else if (rootAffinity != null) {
- out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
- }
- out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
- out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
- out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
- out.attribute(null, ATTR_USERID, String.valueOf(userId));
- out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
- out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
- out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
- out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
- if (lastDescription != null) {
- out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
- }
- if (lastTaskDescription != null) {
- lastTaskDescription.saveToXml(out);
- }
- out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
- out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
- out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
- out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
- out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
- out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
- out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
- out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
- String.valueOf(mSupportsPictureInPicture));
- if (mLastNonFullscreenBounds != null) {
- out.attribute(
- null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
- }
- out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth));
- out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight));
- out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION));
-
- if (affinityIntent != null) {
- out.startTag(null, TAG_AFFINITYINTENT);
- affinityIntent.saveToXml(out);
- out.endTag(null, TAG_AFFINITYINTENT);
- }
-
- out.startTag(null, TAG_INTENT);
- intent.saveToXml(out);
- out.endTag(null, TAG_INTENT);
-
- final ArrayList<ActivityRecord> activities = mActivities;
- final int numActivities = activities.size();
- for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
- final ActivityRecord r = activities.get(activityNdx);
- if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() ||
- ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
- | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) &&
- activityNdx > 0) {
- // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
- break;
- }
- out.startTag(null, TAG_ACTIVITY);
- r.saveToXml(out);
- out.endTag(null, TAG_ACTIVITY);
- }
- }
-
- static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
- throws IOException, XmlPullParserException {
- Intent intent = null;
- Intent affinityIntent = null;
- ArrayList<ActivityRecord> activities = new ArrayList<>();
- ComponentName realActivity = null;
- boolean realActivitySuspended = false;
- ComponentName origActivity = null;
- String affinity = null;
- String rootAffinity = null;
- boolean hasRootAffinity = false;
- boolean rootHasReset = false;
- boolean autoRemoveRecents = false;
- boolean askedCompatMode = false;
- int taskType = 0;
- int userId = 0;
- boolean userSetupComplete = true;
- int effectiveUid = -1;
- String lastDescription = null;
- long lastTimeOnTop = 0;
- boolean neverRelinquishIdentity = true;
- int taskId = INVALID_TASK_ID;
- final int outerDepth = in.getDepth();
- TaskDescription taskDescription = new TaskDescription();
- int taskAffiliation = INVALID_TASK_ID;
- int taskAffiliationColor = 0;
- int prevTaskId = INVALID_TASK_ID;
- int nextTaskId = INVALID_TASK_ID;
- int callingUid = -1;
- String callingPackage = "";
- int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
- boolean supportsPictureInPicture = false;
- Rect bounds = null;
- int minWidth = INVALID_MIN_SIZE;
- int minHeight = INVALID_MIN_SIZE;
- int persistTaskVersion = 0;
-
- for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
- final String attrName = in.getAttributeName(attrNdx);
- final String attrValue = in.getAttributeValue(attrNdx);
- if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" +
- attrName + " value=" + attrValue);
- if (ATTR_TASKID.equals(attrName)) {
- if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue);
- } else if (ATTR_REALACTIVITY.equals(attrName)) {
- realActivity = ComponentName.unflattenFromString(attrValue);
- } else if (ATTR_REALACTIVITY_SUSPENDED.equals(attrName)) {
- realActivitySuspended = Boolean.valueOf(attrValue);
- } else if (ATTR_ORIGACTIVITY.equals(attrName)) {
- origActivity = ComponentName.unflattenFromString(attrValue);
- } else if (ATTR_AFFINITY.equals(attrName)) {
- affinity = attrValue;
- } else if (ATTR_ROOT_AFFINITY.equals(attrName)) {
- rootAffinity = attrValue;
- hasRootAffinity = true;
- } else if (ATTR_ROOTHASRESET.equals(attrName)) {
- rootHasReset = Boolean.parseBoolean(attrValue);
- } else if (ATTR_AUTOREMOVERECENTS.equals(attrName)) {
- autoRemoveRecents = Boolean.parseBoolean(attrValue);
- } else if (ATTR_ASKEDCOMPATMODE.equals(attrName)) {
- askedCompatMode = Boolean.parseBoolean(attrValue);
- } else if (ATTR_USERID.equals(attrName)) {
- userId = Integer.parseInt(attrValue);
- } else if (ATTR_USER_SETUP_COMPLETE.equals(attrName)) {
- userSetupComplete = Boolean.parseBoolean(attrValue);
- } else if (ATTR_EFFECTIVE_UID.equals(attrName)) {
- effectiveUid = Integer.parseInt(attrValue);
- } else if (ATTR_TASKTYPE.equals(attrName)) {
- taskType = Integer.parseInt(attrValue);
- } else if (ATTR_LASTDESCRIPTION.equals(attrName)) {
- lastDescription = attrValue;
- } else if (ATTR_LASTTIMEMOVED.equals(attrName)) {
- lastTimeOnTop = Long.parseLong(attrValue);
- } else if (ATTR_NEVERRELINQUISH.equals(attrName)) {
- neverRelinquishIdentity = Boolean.parseBoolean(attrValue);
- } else if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
- taskDescription.restoreFromXml(attrName, attrValue);
- } else if (ATTR_TASK_AFFILIATION.equals(attrName)) {
- taskAffiliation = Integer.parseInt(attrValue);
- } else if (ATTR_PREV_AFFILIATION.equals(attrName)) {
- prevTaskId = Integer.parseInt(attrValue);
- } else if (ATTR_NEXT_AFFILIATION.equals(attrName)) {
- nextTaskId = Integer.parseInt(attrValue);
- } else if (ATTR_TASK_AFFILIATION_COLOR.equals(attrName)) {
- taskAffiliationColor = Integer.parseInt(attrValue);
- } else if (ATTR_CALLING_UID.equals(attrName)) {
- callingUid = Integer.parseInt(attrValue);
- } else if (ATTR_CALLING_PACKAGE.equals(attrName)) {
- callingPackage = attrValue;
- } else if (ATTR_RESIZE_MODE.equals(attrName)) {
- resizeMode = Integer.parseInt(attrValue);
- } else if (ATTR_SUPPORTS_PICTURE_IN_PICTURE.equals(attrName)) {
- supportsPictureInPicture = Boolean.parseBoolean(attrValue);
- } else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) {
- bounds = Rect.unflattenFromString(attrValue);
- } else if (ATTR_MIN_WIDTH.equals(attrName)) {
- minWidth = Integer.parseInt(attrValue);
- } else if (ATTR_MIN_HEIGHT.equals(attrName)) {
- minHeight = Integer.parseInt(attrValue);
- } else if (ATTR_PERSIST_TASK_VERSION.equals(attrName)) {
- persistTaskVersion = Integer.parseInt(attrValue);
- } else {
- Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
- }
- }
-
- int event;
- while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
- (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
- if (event == XmlPullParser.START_TAG) {
- final String name = in.getName();
- if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" +
- name);
- if (TAG_AFFINITYINTENT.equals(name)) {
- affinityIntent = Intent.restoreFromXml(in);
- } else if (TAG_INTENT.equals(name)) {
- intent = Intent.restoreFromXml(in);
- } else if (TAG_ACTIVITY.equals(name)) {
- ActivityRecord activity = ActivityRecord.restoreFromXml(in, stackSupervisor);
- if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" +
- activity);
- if (activity != null) {
- activities.add(activity);
- }
- } else {
- Slog.e(TAG, "restoreTask: Unexpected name=" + name);
- XmlUtils.skipCurrentTag(in);
- }
- }
- }
- if (!hasRootAffinity) {
- rootAffinity = affinity;
- } else if ("@".equals(rootAffinity)) {
- rootAffinity = null;
- }
- if (effectiveUid <= 0) {
- Intent checkIntent = intent != null ? intent : affinityIntent;
- effectiveUid = 0;
- if (checkIntent != null) {
- IPackageManager pm = AppGlobals.getPackageManager();
- try {
- ApplicationInfo ai = pm.getApplicationInfo(
- checkIntent.getComponent().getPackageName(),
- PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
- if (ai != null) {
- effectiveUid = ai.uid;
- }
- } catch (RemoteException e) {
- }
- }
- Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
- + ": effectiveUid=" + effectiveUid);
- }
-
- if (persistTaskVersion < 1) {
- // We need to convert the resize mode of home activities saved before version one if
- // they are marked as RESIZE_MODE_RESIZEABLE to RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION
- // since we didn't have that differentiation before version 1 and the system didn't
- // resize home activities before then.
- if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) {
- resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
- }
- } else {
- // This activity has previously marked itself explicitly as both resizeable and
- // supporting picture-in-picture. Since there is no longer a requirement for
- // picture-in-picture activities to be resizeable, we can mark this simply as
- // resizeable and supporting picture-in-picture separately.
- if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) {
- resizeMode = RESIZE_MODE_RESIZEABLE;
- supportsPictureInPicture = true;
- }
- }
-
- final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
- affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset,
- autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
- activities, lastTimeOnTop, neverRelinquishIdentity, taskDescription,
- taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid,
- callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended,
- userSetupComplete, minWidth, minHeight);
- task.updateOverrideConfiguration(bounds);
-
- for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
- activities.get(activityNdx).setTask(task);
- }
-
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
- return task;
- }
-
private void adjustForMinimalTaskDimensions(Rect bounds) {
if (bounds == null) {
return;
@@ -1990,7 +1735,6 @@
final Rect currentBounds = getOverrideBounds();
mTmpConfig.setTo(getOverrideConfiguration());
- final boolean oldMatchParentBounds = matchParentBounds();
final Configuration newConfig = getOverrideConfiguration();
final boolean matchParentBounds = bounds == null || bounds.isEmpty();
@@ -2013,12 +1757,17 @@
mTmpRect.right != bounds.right, mTmpRect.bottom != bounds.bottom);
}
onOverrideConfigurationChanged(newConfig);
+ return !mTmpConfig.equals(newConfig);
+ }
- if (matchParentBounds != oldMatchParentBounds) {
+ @Override
+ public void onConfigurationChanged(Configuration newParentConfig) {
+ final boolean wasInMultiWindowMode = inMultiWindowMode();
+ super.onConfigurationChanged(newParentConfig);
+ if (wasInMultiWindowMode != inMultiWindowMode()) {
mService.mStackSupervisor.scheduleUpdateMultiWindowMode(this);
}
-
- return !mTmpConfig.equals(newConfig);
+ // TODO: Should also take care of Pip mode changes here.
}
/** Clears passed config and fills it with new override values. */
@@ -2315,4 +2064,382 @@
top = base = null;
}
}
+
+ /**
+ * Saves this {@link TaskRecord} to XML using given serializer.
+ */
+ void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
+ if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
+
+ out.attribute(null, ATTR_TASKID, String.valueOf(taskId));
+ if (realActivity != null) {
+ out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
+ }
+ out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended));
+ if (origActivity != null) {
+ out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
+ }
+ // Write affinity, and root affinity if it is different from affinity.
+ // We use the special string "@" for a null root affinity, so we can identify
+ // later whether we were given a root affinity or should just make it the
+ // same as the affinity.
+ if (affinity != null) {
+ out.attribute(null, ATTR_AFFINITY, affinity);
+ if (!affinity.equals(rootAffinity)) {
+ out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
+ }
+ } else if (rootAffinity != null) {
+ out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
+ }
+ out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
+ out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
+ out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
+ out.attribute(null, ATTR_USERID, String.valueOf(userId));
+ out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
+ out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
+ out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
+ out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
+ if (lastDescription != null) {
+ out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
+ }
+ if (lastTaskDescription != null) {
+ lastTaskDescription.saveToXml(out);
+ }
+ out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
+ out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
+ out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
+ out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
+ out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
+ out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
+ out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
+ out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
+ String.valueOf(mSupportsPictureInPicture));
+ if (mLastNonFullscreenBounds != null) {
+ out.attribute(
+ null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
+ }
+ out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth));
+ out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight));
+ out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION));
+
+ if (affinityIntent != null) {
+ out.startTag(null, TAG_AFFINITYINTENT);
+ affinityIntent.saveToXml(out);
+ out.endTag(null, TAG_AFFINITYINTENT);
+ }
+
+ out.startTag(null, TAG_INTENT);
+ intent.saveToXml(out);
+ out.endTag(null, TAG_INTENT);
+
+ final ArrayList<ActivityRecord> activities = mActivities;
+ final int numActivities = activities.size();
+ for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
+ final ActivityRecord r = activities.get(activityNdx);
+ if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() ||
+ ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
+ | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) &&
+ activityNdx > 0) {
+ // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
+ break;
+ }
+ out.startTag(null, TAG_ACTIVITY);
+ r.saveToXml(out);
+ out.endTag(null, TAG_ACTIVITY);
+ }
+ }
+
+ @VisibleForTesting
+ static TaskRecordFactory getTaskRecordFactory() {
+ if (sTaskRecordFactory == null) {
+ setTaskRecordFactory(new TaskRecordFactory());
+ }
+ return sTaskRecordFactory;
+ }
+
+ static void setTaskRecordFactory(TaskRecordFactory factory) {
+ sTaskRecordFactory = factory;
+ }
+
+ static TaskRecord create(ActivityManagerService service, int taskId, ActivityInfo info,
+ Intent intent, IVoiceInteractionSession voiceSession,
+ IVoiceInteractor voiceInteractor) {
+ return getTaskRecordFactory().create(
+ service, taskId, info, intent, voiceSession, voiceInteractor);
+ }
+
+ static TaskRecord create(ActivityManagerService service, int taskId, ActivityInfo info,
+ Intent intent, TaskDescription taskDescription) {
+ return getTaskRecordFactory().create(service, taskId, info, intent, taskDescription);
+ }
+
+ static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
+ throws IOException, XmlPullParserException {
+ return getTaskRecordFactory().restoreFromXml(in, stackSupervisor);
+ }
+
+ /**
+ * A factory class used to create {@link TaskRecord} or its subclass if any. This can be
+ * specified when system boots by setting it with
+ * {@link #setTaskRecordFactory(TaskRecordFactory)}.
+ */
+ static class TaskRecordFactory {
+
+ TaskRecord create(ActivityManagerService service, int taskId, ActivityInfo info,
+ Intent intent, IVoiceInteractionSession voiceSession,
+ IVoiceInteractor voiceInteractor) {
+ return new TaskRecord(
+ service, taskId, info, intent, voiceSession, voiceInteractor);
+ }
+
+ TaskRecord create(ActivityManagerService service, int taskId, ActivityInfo info,
+ Intent intent, TaskDescription taskDescription) {
+ return new TaskRecord(service, taskId, info, intent, taskDescription);
+ }
+
+ /**
+ * Should only be used when we're restoring {@link TaskRecord} from storage.
+ */
+ TaskRecord create(ActivityManagerService service, int taskId, Intent intent,
+ Intent affinityIntent, String affinity, String rootAffinity,
+ ComponentName realActivity, ComponentName origActivity, boolean rootWasReset,
+ boolean autoRemoveRecents, boolean askedCompatMode, int userId,
+ int effectiveUid, String lastDescription, ArrayList<ActivityRecord> activities,
+ long lastTimeMoved, boolean neverRelinquishIdentity,
+ TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId,
+ int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
+ int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended,
+ boolean userSetupComplete, int minWidth, int minHeight) {
+ return new TaskRecord(service, taskId, intent, affinityIntent, affinity,
+ rootAffinity, realActivity, origActivity, rootWasReset, autoRemoveRecents,
+ askedCompatMode, userId, effectiveUid, lastDescription, activities,
+ lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation,
+ prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage,
+ resizeMode, supportsPictureInPicture, realActivitySuspended, userSetupComplete,
+ minWidth, minHeight);
+ }
+
+ TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
+ throws IOException, XmlPullParserException {
+ Intent intent = null;
+ Intent affinityIntent = null;
+ ArrayList<ActivityRecord> activities = new ArrayList<>();
+ ComponentName realActivity = null;
+ boolean realActivitySuspended = false;
+ ComponentName origActivity = null;
+ String affinity = null;
+ String rootAffinity = null;
+ boolean hasRootAffinity = false;
+ boolean rootHasReset = false;
+ boolean autoRemoveRecents = false;
+ boolean askedCompatMode = false;
+ int taskType = 0;
+ int userId = 0;
+ boolean userSetupComplete = true;
+ int effectiveUid = -1;
+ String lastDescription = null;
+ long lastTimeOnTop = 0;
+ boolean neverRelinquishIdentity = true;
+ int taskId = INVALID_TASK_ID;
+ final int outerDepth = in.getDepth();
+ TaskDescription taskDescription = new TaskDescription();
+ int taskAffiliation = INVALID_TASK_ID;
+ int taskAffiliationColor = 0;
+ int prevTaskId = INVALID_TASK_ID;
+ int nextTaskId = INVALID_TASK_ID;
+ int callingUid = -1;
+ String callingPackage = "";
+ int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
+ boolean supportsPictureInPicture = false;
+ Rect bounds = null;
+ int minWidth = INVALID_MIN_SIZE;
+ int minHeight = INVALID_MIN_SIZE;
+ int persistTaskVersion = 0;
+
+ for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
+ final String attrName = in.getAttributeName(attrNdx);
+ final String attrValue = in.getAttributeValue(attrNdx);
+ if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" +
+ attrName + " value=" + attrValue);
+ switch (attrName) {
+ case ATTR_TASKID:
+ if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue);
+ break;
+ case ATTR_REALACTIVITY:
+ realActivity = ComponentName.unflattenFromString(attrValue);
+ break;
+ case ATTR_REALACTIVITY_SUSPENDED:
+ realActivitySuspended = Boolean.valueOf(attrValue);
+ break;
+ case ATTR_ORIGACTIVITY:
+ origActivity = ComponentName.unflattenFromString(attrValue);
+ break;
+ case ATTR_AFFINITY:
+ affinity = attrValue;
+ break;
+ case ATTR_ROOT_AFFINITY:
+ rootAffinity = attrValue;
+ hasRootAffinity = true;
+ break;
+ case ATTR_ROOTHASRESET:
+ rootHasReset = Boolean.parseBoolean(attrValue);
+ break;
+ case ATTR_AUTOREMOVERECENTS:
+ autoRemoveRecents = Boolean.parseBoolean(attrValue);
+ break;
+ case ATTR_ASKEDCOMPATMODE:
+ askedCompatMode = Boolean.parseBoolean(attrValue);
+ break;
+ case ATTR_USERID:
+ userId = Integer.parseInt(attrValue);
+ break;
+ case ATTR_USER_SETUP_COMPLETE:
+ userSetupComplete = Boolean.parseBoolean(attrValue);
+ break;
+ case ATTR_EFFECTIVE_UID:
+ effectiveUid = Integer.parseInt(attrValue);
+ break;
+ case ATTR_TASKTYPE:
+ taskType = Integer.parseInt(attrValue);
+ break;
+ case ATTR_LASTDESCRIPTION:
+ lastDescription = attrValue;
+ break;
+ case ATTR_LASTTIMEMOVED:
+ lastTimeOnTop = Long.parseLong(attrValue);
+ break;
+ case ATTR_NEVERRELINQUISH:
+ neverRelinquishIdentity = Boolean.parseBoolean(attrValue);
+ break;
+ case ATTR_TASK_AFFILIATION:
+ taskAffiliation = Integer.parseInt(attrValue);
+ break;
+ case ATTR_PREV_AFFILIATION:
+ prevTaskId = Integer.parseInt(attrValue);
+ break;
+ case ATTR_NEXT_AFFILIATION:
+ nextTaskId = Integer.parseInt(attrValue);
+ break;
+ case ATTR_TASK_AFFILIATION_COLOR:
+ taskAffiliationColor = Integer.parseInt(attrValue);
+ break;
+ case ATTR_CALLING_UID:
+ callingUid = Integer.parseInt(attrValue);
+ break;
+ case ATTR_CALLING_PACKAGE:
+ callingPackage = attrValue;
+ break;
+ case ATTR_RESIZE_MODE:
+ resizeMode = Integer.parseInt(attrValue);
+ break;
+ case ATTR_SUPPORTS_PICTURE_IN_PICTURE:
+ supportsPictureInPicture = Boolean.parseBoolean(attrValue);
+ break;
+ case ATTR_NON_FULLSCREEN_BOUNDS:
+ bounds = Rect.unflattenFromString(attrValue);
+ break;
+ case ATTR_MIN_WIDTH:
+ minWidth = Integer.parseInt(attrValue);
+ break;
+ case ATTR_MIN_HEIGHT:
+ minHeight = Integer.parseInt(attrValue);
+ break;
+ case ATTR_PERSIST_TASK_VERSION:
+ persistTaskVersion = Integer.parseInt(attrValue);
+ break;
+ default:
+ if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
+ taskDescription.restoreFromXml(attrName, attrValue);
+ } else {
+ Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
+ }
+ }
+ }
+
+ int event;
+ while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
+ (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
+ if (event == XmlPullParser.START_TAG) {
+ final String name = in.getName();
+ if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
+ "TaskRecord: START_TAG name=" + name);
+ if (TAG_AFFINITYINTENT.equals(name)) {
+ affinityIntent = Intent.restoreFromXml(in);
+ } else if (TAG_INTENT.equals(name)) {
+ intent = Intent.restoreFromXml(in);
+ } else if (TAG_ACTIVITY.equals(name)) {
+ ActivityRecord activity =
+ ActivityRecord.restoreFromXml(in, stackSupervisor);
+ if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" +
+ activity);
+ if (activity != null) {
+ activities.add(activity);
+ }
+ } else {
+ Slog.e(TAG, "restoreTask: Unexpected name=" + name);
+ XmlUtils.skipCurrentTag(in);
+ }
+ }
+ }
+ if (!hasRootAffinity) {
+ rootAffinity = affinity;
+ } else if ("@".equals(rootAffinity)) {
+ rootAffinity = null;
+ }
+ if (effectiveUid <= 0) {
+ Intent checkIntent = intent != null ? intent : affinityIntent;
+ effectiveUid = 0;
+ if (checkIntent != null) {
+ IPackageManager pm = AppGlobals.getPackageManager();
+ try {
+ ApplicationInfo ai = pm.getApplicationInfo(
+ checkIntent.getComponent().getPackageName(),
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
+ if (ai != null) {
+ effectiveUid = ai.uid;
+ }
+ } catch (RemoteException e) {
+ }
+ }
+ Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
+ + ": effectiveUid=" + effectiveUid);
+ }
+
+ if (persistTaskVersion < 1) {
+ // We need to convert the resize mode of home activities saved before version one if
+ // they are marked as RESIZE_MODE_RESIZEABLE to
+ // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation
+ // before version 1 and the system didn't resize home activities before then.
+ if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) {
+ resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+ }
+ } else {
+ // This activity has previously marked itself explicitly as both resizeable and
+ // supporting picture-in-picture. Since there is no longer a requirement for
+ // picture-in-picture activities to be resizeable, we can mark this simply as
+ // resizeable and supporting picture-in-picture separately.
+ if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) {
+ resizeMode = RESIZE_MODE_RESIZEABLE;
+ supportsPictureInPicture = true;
+ }
+ }
+
+ final TaskRecord task = create(stackSupervisor.mService, taskId, intent, affinityIntent,
+ affinity, rootAffinity, realActivity, origActivity, rootHasReset,
+ autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
+ activities, lastTimeOnTop, neverRelinquishIdentity, taskDescription,
+ taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid,
+ callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended,
+ userSetupComplete, minWidth, minHeight);
+ task.updateOverrideConfiguration(bounds);
+
+ for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
+ activities.get(activityNdx).setTask(task);
+ }
+
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
+ return task;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/UnsupportedCompileSdkDialog.java b/services/core/java/com/android/server/am/UnsupportedCompileSdkDialog.java
index 600589a..b6f6ae6 100644
--- a/services/core/java/com/android/server/am/UnsupportedCompileSdkDialog.java
+++ b/services/core/java/com/android/server/am/UnsupportedCompileSdkDialog.java
@@ -39,7 +39,7 @@
final PackageManager pm = context.getPackageManager();
final CharSequence label = appInfo.loadSafeLabel(pm);
final CharSequence message = context.getString(R.string.unsupported_compile_sdk_message,
- label, appInfo.compileSdkVersionCodename);
+ label);
final AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setPositiveButton(R.string.ok, null)
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 4e3d8d2..6bd599b 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -24,6 +24,7 @@
import static android.app.ActivityManager.USER_OP_SUCCESS;
import static android.os.Process.SHELL_UID;
import static android.os.Process.SYSTEM_UID;
+
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -37,6 +38,7 @@
import static com.android.server.am.UserState.STATE_RUNNING_UNLOCKING;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AppGlobals;
@@ -830,6 +832,9 @@
private IStorageManager getStorageManager() {
return IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
}
+ boolean startUser(final int userId, final boolean foreground) {
+ return startUser(userId, foreground, null);
+ }
/**
* Start user, if its not already running.
@@ -860,7 +865,10 @@
* @param foreground true if user should be brought to the foreground
* @return true if the user has been successfully started
*/
- boolean startUser(final int userId, final boolean foreground) {
+ boolean startUser(
+ final int userId,
+ final boolean foreground,
+ @Nullable IProgressListener unlockListener) {
if (mInjector.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: switchUser() from pid="
@@ -918,6 +926,10 @@
final Integer userIdInt = userId;
mUserLru.remove(userIdInt);
mUserLru.add(userIdInt);
+
+ if (unlockListener != null) {
+ uss.mUnlockProgress.addListener(unlockListener);
+ }
}
if (updateUmState) {
mInjector.getUserManagerInternal().setUserState(userId, uss.state);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 15a418dc..efa0bf8 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1645,6 +1645,11 @@
};
private int getNewRingerMode(int stream, int index, int flags) {
+ // setRingerMode does nothing if the device is single volume,so the value would be unchanged
+ if (mIsSingleVolume) {
+ return getRingerModeExternal();
+ }
+
// setting volume on ui sounds stream type also controls silent mode
if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
(stream == getUiSoundsStreamType())) {
@@ -3691,7 +3696,7 @@
private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted,
String caller, int flags) {
int result = FLAG_ADJUST_VOLUME;
- if (isPlatformTelevision()) {
+ if (isPlatformTelevision() || mIsSingleVolume) {
return result;
}
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index e243e56..979beed 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -244,7 +244,7 @@
event.timestampMs = timestampMs;
event.uid = uid;
event.ethertype = ethertype;
- event.dstHwAddr = new MacAddress(dstHw);
+ event.dstHwAddr = MacAddress.fromBytes(dstHw);
event.srcIp = srcIp;
event.dstIp = dstIp;
event.ipNextHeader = ipNextHeader;
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 9cd52d7..bdfd4bd 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -323,7 +323,7 @@
private final BroadcastReceiver mAccountsUpdatedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- EndPoint target = new EndPoint(null, null, context.getUserId());
+ EndPoint target = new EndPoint(null, null, getSendingUserId());
updateRunningAccounts(target /* sync targets for user */);
}
};
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 90888f0..61b6fa0 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -34,6 +34,7 @@
import android.os.BatteryManager;
import android.os.Environment;
import android.os.Handler;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -162,7 +163,10 @@
UserHandle.USER_CURRENT);
mSensorListener = new SensorListener();
- mInjector.registerSensorListener(mContext, mSensorListener);
+
+ if (mInjector.isInteractive(mContext)) {
+ mInjector.registerSensorListener(mContext, mSensorListener, mBgHandler);
+ }
mSettingsObserver = new SettingsObserver(mBgHandler);
mInjector.registerBrightnessObserver(mContentResolver, mSettingsObserver);
@@ -170,6 +174,8 @@
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_SHUTDOWN);
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ intentFilter.addAction(Intent.ACTION_SCREEN_ON);
+ intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
mBroadcastReceiver = new Receiver();
mInjector.registerReceiver(mContext, mBroadcastReceiver, intentFilter);
@@ -190,9 +196,10 @@
/**
* @param userId userId to fetch data for.
+ * @param includePackage if false we will null out BrightnessChangeEvent.packageName
* @return List of recent {@link BrightnessChangeEvent}s
*/
- public ParceledListSlice<BrightnessChangeEvent> getEvents(int userId) {
+ public ParceledListSlice<BrightnessChangeEvent> getEvents(int userId, boolean includePackage) {
// TODO include apps from any managed profiles in the brightness information.
BrightnessChangeEvent[] events;
synchronized (mEventsLock) {
@@ -201,7 +208,13 @@
ArrayList<BrightnessChangeEvent> out = new ArrayList<>(events.length);
for (int i = 0; i < events.length; ++i) {
if (events[i].userId == userId) {
- out.add(events[i]);
+ if (includePackage) {
+ out.add(events[i]);
+ } else {
+ BrightnessChangeEvent event = new BrightnessChangeEvent((events[i]));
+ event.packageName = null;
+ out.add(event);
+ }
}
}
return new ParceledListSlice<>(out);
@@ -584,6 +597,11 @@
if (level != -1 && scale != 0) {
batteryLevelChanged(level, scale);
}
+ } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
+ mInjector.unregisterSensorListener(mContext, mSensorListener);
+ } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
+ mInjector.registerSensorListener(mContext, mSensorListener,
+ mInjector.getBackgroundHandler());
}
}
}
@@ -591,11 +609,11 @@
@VisibleForTesting
static class Injector {
public void registerSensorListener(Context context,
- SensorEventListener sensorListener) {
+ SensorEventListener sensorListener, Handler handler) {
SensorManager sensorManager = context.getSystemService(SensorManager.class);
Sensor lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
sensorManager.registerListener(sensorListener,
- lightSensor, SensorManager.SENSOR_DELAY_NORMAL);
+ lightSensor, SensorManager.SENSOR_DELAY_NORMAL, handler);
}
public void unregisterSensorListener(Context context, SensorEventListener sensorListener) {
@@ -675,5 +693,9 @@
public void cancelIdleJob(Context context) {
BrightnessIdleJob.cancelJob(context);
}
+
+ public boolean isInteractive(Context context) {
+ return context.getSystemService(PowerManager.class).isInteractive();
+ }
}
}
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index af8ecad..75f3056 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -33,11 +33,8 @@
import android.opengl.Matrix;
import android.os.Handler;
import android.os.Looper;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings.Secure;
-import android.service.vr.IVrManager;
-import android.service.vr.IVrStateCallbacks;
import android.util.MathUtils;
import android.util.Slog;
import android.view.animation.AnimationUtils;
@@ -51,7 +48,6 @@
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
-import java.util.concurrent.atomic.AtomicBoolean;
import com.android.internal.R;
@@ -84,32 +80,6 @@
private static final ColorMatrixEvaluator COLOR_MATRIX_EVALUATOR = new ColorMatrixEvaluator();
private final Handler mHandler;
- private final AtomicBoolean mIgnoreAllColorMatrixChanges = new AtomicBoolean();
- private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
- @Override
- public void onVrStateChanged(final boolean enabled) {
- // Turn off all night mode display stuff while device is in VR mode.
- mIgnoreAllColorMatrixChanges.set(enabled);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- // Cancel in-progress animations
- if (mColorMatrixAnimator != null) {
- mColorMatrixAnimator.cancel();
- }
-
- final DisplayTransformManager dtm =
- getLocalService(DisplayTransformManager.class);
- if (enabled) {
- dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, MATRIX_IDENTITY);
- } else if (mController != null && mController.isActivated()) {
- setMatrix(mController.getColorTemperature(), mMatrixNight);
- dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, mMatrixNight);
- }
- }
- });
- }
- };
private float[] mMatrixNight = new float[16];
@@ -136,18 +106,6 @@
@Override
public void onBootPhase(int phase) {
- if (phase >= PHASE_SYSTEM_SERVICES_READY) {
- final IVrManager vrManager = IVrManager.Stub.asInterface(
- getBinderService(Context.VR_SERVICE));
- if (vrManager != null) {
- try {
- vrManager.registerListener(mVrStateCallbacks);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to register VR mode state listener: " + e);
- }
- }
- }
-
if (phase >= PHASE_BOOT_COMPLETED) {
mBootCompleted = true;
@@ -359,11 +317,6 @@
mColorMatrixAnimator.cancel();
}
- // Don't do any color matrix change animations if we are ignoring them anyway.
- if (mIgnoreAllColorMatrixChanges.get()) {
- return;
- }
-
final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
final float[] from = dtm.getColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY);
final float[] to = mIsActivated ? mMatrixNight : MATRIX_IDENTITY;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 379aaad..19a74d7 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -29,6 +29,7 @@
import android.Manifest;
import android.annotation.NonNull;
+import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
@@ -1752,14 +1753,30 @@
}
@Override // Binder call
- public ParceledListSlice<BrightnessChangeEvent> getBrightnessEvents() {
+ public ParceledListSlice<BrightnessChangeEvent> getBrightnessEvents(String callingPackage) {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.BRIGHTNESS_SLIDER_USAGE,
"Permission to read brightness events.");
- int userId = UserHandle.getUserId(Binder.getCallingUid());
+
+ final int callingUid = Binder.getCallingUid();
+ AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+ final int mode = appOpsManager.checkOp(AppOpsManager.OP_GET_USAGE_STATS,
+ callingUid, callingPackage);
+ final boolean hasUsageStats;
+ if (mode == AppOpsManager.MODE_DEFAULT) {
+ // The default behavior here is to check if PackageManager has given the app
+ // permission.
+ hasUsageStats = mContext.checkCallingPermission(
+ Manifest.permission.PACKAGE_USAGE_STATS)
+ == PackageManager.PERMISSION_GRANTED;
+ } else {
+ hasUsageStats = mode == AppOpsManager.MODE_ALLOWED;
+ }
+
+ final int userId = UserHandle.getUserId(callingUid);
final long token = Binder.clearCallingIdentity();
try {
- return mBrightnessTracker.getEvents(userId);
+ return mBrightnessTracker.getEvents(userId, hasUsageStats);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 4af86a0..3f014b5 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -29,7 +29,7 @@
import android.app.job.JobScheduler;
import android.app.job.JobService;
import android.app.job.JobWorkItem;
-import android.app.usage.AppStandby;
+import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
import android.content.BroadcastReceiver;
@@ -2074,10 +2074,10 @@
public static int standbyBucketToBucketIndex(int bucket) {
// Normalize AppStandby constants to indices into our bookkeeping
- if (bucket == AppStandby.STANDBY_BUCKET_NEVER) return 4;
- else if (bucket >= AppStandby.STANDBY_BUCKET_RARE) return 3;
- else if (bucket >= AppStandby.STANDBY_BUCKET_FREQUENT) return 2;
- else if (bucket >= AppStandby.STANDBY_BUCKET_WORKING_SET) return 1;
+ if (bucket == UsageStatsManager.STANDBY_BUCKET_NEVER) return 4;
+ else if (bucket >= UsageStatsManager.STANDBY_BUCKET_RARE) return 3;
+ else if (bucket >= UsageStatsManager.STANDBY_BUCKET_FREQUENT) return 2;
+ else if (bucket >= UsageStatsManager.STANDBY_BUCKET_WORKING_SET) return 1;
else return 0;
}
diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
index f67bd04..fc4015d 100644
--- a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -16,19 +16,12 @@
package com.android.server.job.controllers;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.os.IDeviceIdleController;
-import android.os.PowerManager;
-import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.util.Pair;
import android.util.Slog;
-import android.util.SparseBooleanArray;
import com.android.internal.util.ArrayUtils;
import com.android.server.ForceAppStandbyTracker;
@@ -37,7 +30,6 @@
import com.android.server.job.JobStore;
import java.io.PrintWriter;
-import java.util.function.Predicate;
public final class BackgroundJobsController extends StateController {
@@ -51,9 +43,6 @@
private final JobSchedulerService mJobSchedulerService;
private final IDeviceIdleController mDeviceIdleController;
- private int[] mPowerWhitelistedUserAppIds;
- private int[] mTempWhitelistedAppIds;
-
private final ForceAppStandbyTracker mForceAppStandbyTracker;
@@ -67,28 +56,6 @@
}
}
- private BroadcastReceiver mDozeWhitelistReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- synchronized (mLock) {
- try {
- switch (intent.getAction()) {
- case PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED:
- mPowerWhitelistedUserAppIds =
- mDeviceIdleController.getAppIdUserWhitelist();
- break;
- case PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED:
- mTempWhitelistedAppIds = mDeviceIdleController.getAppIdTempWhitelist();
- break;
- }
- } catch (RemoteException rexc) {
- Slog.e(LOG_TAG, "Device idle controller not reachable");
- }
- updateAllJobRestrictionsLocked();
- }
- }
- };
-
private BackgroundJobsController(JobSchedulerService service, Context context, Object lock) {
super(service, context, lock);
mJobSchedulerService = service;
@@ -97,19 +64,6 @@
mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context);
- try {
- mPowerWhitelistedUserAppIds = mDeviceIdleController.getAppIdUserWhitelist();
- mTempWhitelistedAppIds = mDeviceIdleController.getAppIdTempWhitelist();
- } catch (RemoteException rexc) {
- // Shouldn't happen as they are in the same process.
- Slog.e(LOG_TAG, "AppOps or DeviceIdle service not reachable", rexc);
- }
- IntentFilter powerWhitelistFilter = new IntentFilter();
- powerWhitelistFilter.addAction(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
- powerWhitelistFilter.addAction(PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED);
- context.registerReceiverAsUser(mDozeWhitelistReceiver, UserHandle.ALL, powerWhitelistFilter,
- null, null);
-
mForceAppStandbyTracker.addListener(mForceAppStandbyListener);
mForceAppStandbyTracker.start();
}
@@ -128,31 +82,7 @@
public void dumpControllerStateLocked(final PrintWriter pw, final int filterUid) {
pw.println("BackgroundJobsController");
- pw.print("Force all apps standby: ");
- pw.println(mForceAppStandbyTracker.isForceAllAppsStandbyEnabled());
-
- pw.print("Foreground uids: [");
- final SparseBooleanArray foregroundUids = mForceAppStandbyTracker.getForegroudUids();
-
- String sep = "";
- for (int i = 0; i < foregroundUids.size(); i++) {
- if (foregroundUids.valueAt(i)) {
- pw.print(sep);
- pw.print(UserHandle.formatUid(foregroundUids.keyAt(i)));
- sep = " ";
- }
- }
- pw.println("]");
-
- pw.println("Restricted packages:");
- for (Pair<Integer, String> uidAndPackage
- : mForceAppStandbyTracker.getRestrictedUidPackages()) {
- pw.print(" ");
- pw.print(UserHandle.formatUid(uidAndPackage.first));
- pw.print(" ");
- pw.print(uidAndPackage.second);
- pw.println();
- }
+ mForceAppStandbyTracker.dump(pw, "");
pw.println("Job state:");
mJobSchedulerService.getJobStore().forEachJob((jobStatus) -> {
@@ -165,15 +95,17 @@
pw.print(" from ");
UserHandle.formatUid(pw, uid);
pw.print(mForceAppStandbyTracker.isInForeground(uid) ? " foreground" : " background");
- if (isWhitelistedLocked(uid)) {
+ if (mForceAppStandbyTracker.isUidPowerSaveWhitelisted(uid) ||
+ mForceAppStandbyTracker.isUidTempPowerSaveWhitelisted(uid)) {
pw.print(", whitelisted");
}
pw.print(": ");
pw.print(jobStatus.getSourcePackageName());
- pw.print(" [background restrictions ");
+ pw.print(" [RUN_ANY_IN_BACKGROUND ");
pw.print(mForceAppStandbyTracker.isRunAnyInBackgroundAppOpsAllowed(
- jobStatus.getSourceUid(), jobStatus.getSourcePackageName()) ? "off]" : "on]");
+ jobStatus.getSourceUid(), jobStatus.getSourcePackageName())
+ ? "allowed]" : "disallowed]");
if ((jobStatus.satisfiedConstraints
& JobStatus.CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
@@ -218,19 +150,12 @@
}
}
- private boolean isWhitelistedLocked(int uid) {
- final int appId = UserHandle.getAppId(uid);
- return ArrayUtils.contains(mTempWhitelistedAppIds, appId)
- || ArrayUtils.contains(mPowerWhitelistedUserAppIds, appId);
- }
-
boolean updateSingleJobRestrictionLocked(JobStatus jobStatus) {
final int uid = jobStatus.getSourceUid();
final String packageName = jobStatus.getSourcePackageName();
- final boolean canRun = isWhitelistedLocked(uid)
- || !mForceAppStandbyTracker.isRestricted(uid, packageName);
+ final boolean canRun = !mForceAppStandbyTracker.areJobsRestricted(uid, packageName);
return jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun);
}
@@ -261,13 +186,18 @@
private final Listener mForceAppStandbyListener = new Listener() {
@Override
- public void onRestrictionChanged(int uid, String packageName) {
+ public void updateAllJobs() {
+ updateAllJobRestrictionsLocked();
+ }
+
+ @Override
+ public void updateJobsForUid(int uid) {
updateJobRestrictionsForUidLocked(uid);
}
@Override
- public void onGlobalRestrictionChanged() {
- updateAllJobRestrictionsLocked();
+ public void updateJobsForUidPackage(int uid, String packageName) {
+ updateJobRestrictionsForUidLocked(uid);
}
};
}
diff --git a/services/core/java/com/android/server/location/ContextHubClientBroker.java b/services/core/java/com/android/server/location/ContextHubClientBroker.java
new file mode 100644
index 0000000..41d9feb
--- /dev/null
+++ b/services/core/java/com/android/server/location/ContextHubClientBroker.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright 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.location;
+
+import android.content.Context;
+import android.hardware.contexthub.V1_0.ContextHubMsg;
+import android.hardware.contexthub.V1_0.IContexthub;
+import android.hardware.contexthub.V1_0.Result;
+import android.hardware.location.ContextHubTransaction;
+import android.hardware.location.IContextHubClient;
+import android.hardware.location.IContextHubClientCallback;
+import android.hardware.location.NanoAppMessage;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * A class that acts as a broker for the ContextHubClient, which handles messaging and life-cycle
+ * notification callbacks. This class implements the IContextHubClient object, and the implemented
+ * APIs must be thread-safe.
+ *
+ * @hide
+ */
+public class ContextHubClientBroker extends IContextHubClient.Stub
+ implements IBinder.DeathRecipient {
+ private static final String TAG = "ContextHubClientBroker";
+
+ /*
+ * The context of the service.
+ */
+ private final Context mContext;
+
+ /*
+ * The proxy to talk to the Context Hub HAL.
+ */
+ private final IContexthub mContextHubProxy;
+
+ /*
+ * The manager that registered this client.
+ */
+ private final ContextHubClientManager mClientManager;
+
+ /*
+ * The ID of the hub that this client is attached to.
+ */
+ private final int mAttachedContextHubId;
+
+ /*
+ * The host end point ID of this client.
+ */
+ private final short mHostEndPointId;
+
+ /*
+ * The remote callback interface for this client.
+ */
+ private final IContextHubClientCallback mCallbackInterface;
+
+ /*
+ * false if the connection has been closed by the client, true otherwise.
+ */
+ private final AtomicBoolean mConnectionOpen = new AtomicBoolean(true);
+
+ /* package */ ContextHubClientBroker(
+ Context context, IContexthub contextHubProxy, ContextHubClientManager clientManager,
+ int contextHubId, short hostEndPointId, IContextHubClientCallback callback) {
+ mContext = context;
+ mContextHubProxy = contextHubProxy;
+ mClientManager = clientManager;
+ mAttachedContextHubId = contextHubId;
+ mHostEndPointId = hostEndPointId;
+ mCallbackInterface = callback;
+ }
+
+ /**
+ * Attaches a death recipient for this client
+ *
+ * @throws RemoteException if the client has already died
+ */
+ /* package */ void attachDeathRecipient() throws RemoteException {
+ mCallbackInterface.asBinder().linkToDeath(this, 0 /* flags */);
+ }
+
+ /**
+ * Sends from this client to a nanoapp.
+ *
+ * @param message the message to send
+ * @return the error code of sending the message
+ */
+ @ContextHubTransaction.Result
+ @Override
+ public int sendMessageToNanoApp(NanoAppMessage message) {
+ ContextHubServiceUtil.checkPermissions(mContext);
+
+ int result;
+ if (mConnectionOpen.get()) {
+ ContextHubMsg messageToNanoApp = ContextHubServiceUtil.createHidlContextHubMessage(
+ mHostEndPointId, message);
+
+ try {
+ result = mContextHubProxy.sendMessageToHub(mAttachedContextHubId, messageToNanoApp);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in sendMessageToNanoApp (target hub ID = "
+ + mAttachedContextHubId + ")", e);
+ result = Result.UNKNOWN_FAILURE;
+ }
+ } else {
+ Log.e(TAG, "Failed to send message to nanoapp: client connection is closed");
+ result = Result.UNKNOWN_FAILURE;
+ }
+
+ return ContextHubServiceUtil.toTransactionResult(result);
+ }
+
+ /**
+ * Closes the connection for this client with the service.
+ */
+ @Override
+ public void close() {
+ if (mConnectionOpen.getAndSet(false)) {
+ mClientManager.unregisterClient(mHostEndPointId);
+ }
+ }
+
+ /**
+ * Invoked when the underlying binder of this broker has died at the client process.
+ */
+ public void binderDied() {
+ try {
+ IContextHubClient.Stub.asInterface(this).close();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException while closing client on death", e);
+ }
+ }
+
+ /**
+ * @return the ID of the context hub this client is attached to
+ */
+ /* package */ int getAttachedContextHubId() {
+ return mAttachedContextHubId;
+ }
+
+ /**
+ * @return the host endpoint ID of this client
+ */
+ /* package */ short getHostEndPointId() {
+ return mHostEndPointId;
+ }
+
+ /**
+ * Sends a message to the client associated with this object.
+ *
+ * @param message the message that came from a nanoapp
+ */
+ /* package */ void sendMessageToClient(NanoAppMessage message) {
+ if (mConnectionOpen.get()) {
+ try {
+ mCallbackInterface.onMessageFromNanoApp(message);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException while sending message to client (host endpoint ID = "
+ + mHostEndPointId + ")", e);
+ }
+ }
+ }
+
+ /**
+ * Handles a nanoapp load event.
+ *
+ * @param nanoAppId the ID of the nanoapp that was loaded.
+ */
+ /* package */ void onNanoAppLoaded(long nanoAppId) {
+ if (mConnectionOpen.get()) {
+ try {
+ mCallbackInterface.onNanoAppLoaded(nanoAppId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException while calling onNanoAppLoaded on client"
+ + " (host endpoint ID = " + mHostEndPointId + ")", e);
+ }
+ }
+ }
+
+ /**
+ * Handles a nanoapp unload event.
+ *
+ * @param nanoAppId the ID of the nanoapp that was unloaded.
+ */
+ /* package */ void onNanoAppUnloaded(long nanoAppId) {
+ if (mConnectionOpen.get()) {
+ try {
+ mCallbackInterface.onNanoAppUnloaded(nanoAppId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException while calling onNanoAppUnloaded on client"
+ + " (host endpoint ID = " + mHostEndPointId + ")", e);
+ }
+ }
+ }
+
+ /**
+ * Handles a hub reset for this client.
+ */
+ /* package */ void onHubReset() {
+ if (mConnectionOpen.get()) {
+ try {
+ mCallbackInterface.onHubReset();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException while calling onHubReset on client" +
+ " (host endpoint ID = " + mHostEndPointId + ")", e);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/ContextHubClientManager.java b/services/core/java/com/android/server/location/ContextHubClientManager.java
new file mode 100644
index 0000000..d58a746
--- /dev/null
+++ b/services/core/java/com/android/server/location/ContextHubClientManager.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright 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.location;
+
+import android.content.Context;
+import android.hardware.contexthub.V1_0.ContextHubMsg;
+import android.hardware.contexthub.V1_0.IContexthub;
+import android.hardware.location.IContextHubClient;
+import android.hardware.location.IContextHubClientCallback;
+import android.hardware.location.NanoAppMessage;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.NoSuchElementException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Consumer;
+
+/**
+ * A class that manages registration/unregistration of clients and manages messages to/from clients.
+ *
+ * @hide
+ */
+/* package */ class ContextHubClientManager {
+ private static final String TAG = "ContextHubClientManager";
+
+ /*
+ * The maximum host endpoint ID value that a client can be assigned.
+ */
+ private static final int MAX_CLIENT_ID = 0x7fff;
+
+ /*
+ * Local flag to enable debug logging.
+ */
+ private static final boolean DEBUG_LOG_ENABLED = true;
+
+ /*
+ * The context of the service.
+ */
+ private final Context mContext;
+
+ /*
+ * The proxy to talk to the Context Hub.
+ */
+ private final IContexthub mContextHubProxy;
+
+ /*
+ * A mapping of host endpoint IDs to the ContextHubClientBroker object of registered clients.
+ * A concurrent data structure is used since the registration/unregistration can occur in
+ * multiple threads.
+ */
+ private final ConcurrentHashMap<Short, ContextHubClientBroker> mHostEndPointIdToClientMap =
+ new ConcurrentHashMap<>();
+
+ /*
+ * The next host endpoint ID to start iterating for the next available host endpoint ID.
+ */
+ private int mNextHostEndpointId = 0;
+
+ /* package */ ContextHubClientManager(
+ Context context, IContexthub contextHubProxy) {
+ mContext = context;
+ mContextHubProxy = contextHubProxy;
+ }
+
+ /**
+ * Registers a new client with the service.
+ *
+ * @param clientCallback the callback interface of the client to register
+ * @param contextHubId the ID of the hub this client is attached to
+ *
+ * @return the client interface
+ *
+ * @throws IllegalStateException if max number of clients have already registered
+ */
+ /* package */ IContextHubClient registerClient(
+ IContextHubClientCallback clientCallback, int contextHubId) {
+ ContextHubClientBroker broker = createNewClientBroker(clientCallback, contextHubId);
+
+ try {
+ broker.attachDeathRecipient();
+ } catch (RemoteException e) {
+ // The client process has died, so we close the connection and return null.
+ Log.e(TAG, "Failed to attach death recipient to client");
+ broker.close();
+ return null;
+ }
+
+ Log.d(TAG, "Registered client with host endpoint ID " + broker.getHostEndPointId());
+ return IContextHubClient.Stub.asInterface(broker);
+ }
+
+ /**
+ * Handles a message sent from a nanoapp.
+ *
+ * @param contextHubId the ID of the hub where the nanoapp sent the message from
+ * @param message the message send by a nanoapp
+ */
+ /* package */ void onMessageFromNanoApp(int contextHubId, ContextHubMsg message) {
+ NanoAppMessage clientMessage = ContextHubServiceUtil.createNanoAppMessage(message);
+
+ if (DEBUG_LOG_ENABLED) {
+ String targetAudience = clientMessage.isBroadcastMessage() ? "broadcast" : "unicast";
+ Log.v(TAG, "Received a " + targetAudience + " message from nanoapp 0x"
+ + Long.toHexString(clientMessage.getNanoAppId()));
+ }
+
+ if (clientMessage.isBroadcastMessage()) {
+ broadcastMessage(contextHubId, clientMessage);
+ } else {
+ ContextHubClientBroker proxy = mHostEndPointIdToClientMap.get(message.hostEndPoint);
+ if (proxy != null) {
+ proxy.sendMessageToClient(clientMessage);
+ } else {
+ Log.e(TAG, "Cannot send message to unregistered client (host endpoint ID = "
+ + message.hostEndPoint + ")");
+ }
+ }
+ }
+
+ /**
+ * Unregisters a client from the service.
+ *
+ * This method should be invoked as a result of a client calling the ContextHubClient.close(),
+ * or if the client process has died.
+ *
+ * @param hostEndPointId the host endpoint ID of the client that has died
+ */
+ /* package */ void unregisterClient(short hostEndPointId) {
+ if (mHostEndPointIdToClientMap.remove(hostEndPointId) != null) {
+ Log.d(TAG, "Unregistered client with host endpoint ID " + hostEndPointId);
+ } else {
+ Log.e(TAG, "Cannot unregister non-existing client with host endpoint ID "
+ + hostEndPointId);
+ }
+ }
+
+ /**
+ * Handles a nanoapp load event.
+ *
+ * @param contextHubId the ID of the hub where the nanoapp was loaded.
+ * @param nanoAppId the ID of the nanoapp that was loaded.
+ */
+ /* package */ void onNanoAppLoaded(int contextHubId, long nanoAppId) {
+ forEachClientOfHub(contextHubId, client -> client.onNanoAppLoaded(nanoAppId));
+ }
+
+ /**
+ * Handles a nanoapp unload event.
+ *
+ * @param contextHubId the ID of the hub where the nanoapp was unloaded.
+ * @param nanoAppId the ID of the nanoapp that was unloaded.
+ */
+ /* package */ void onNanoAppUnloaded(int contextHubId, long nanoAppId) {
+ forEachClientOfHub(contextHubId, client -> client.onNanoAppUnloaded(nanoAppId));
+ }
+
+ /**
+ * Handles a hub reset.
+ *
+ * @param contextHubId the ID of the hub that has reset.
+ */
+ /* package */ void onHubReset(int contextHubId) {
+ forEachClientOfHub(contextHubId, client -> client.onHubReset());
+ }
+
+ /**
+ * Creates a new ContextHubClientBroker object for a client and registers it with the client
+ * manager.
+ *
+ * @param clientCallback the callback interface of the client to register
+ * @param contextHubId the ID of the hub this client is attached to
+ *
+ * @return the ContextHubClientBroker object
+ *
+ * @throws IllegalStateException if max number of clients have already registered
+ */
+ private synchronized ContextHubClientBroker createNewClientBroker(
+ IContextHubClientCallback clientCallback, int contextHubId) {
+ if (mHostEndPointIdToClientMap.size() == MAX_CLIENT_ID + 1) {
+ throw new IllegalStateException("Could not register client - max limit exceeded");
+ }
+
+ ContextHubClientBroker broker = null;
+ int id = mNextHostEndpointId;
+ for (int i = 0; i <= MAX_CLIENT_ID; i++) {
+ if (!mHostEndPointIdToClientMap.containsKey(id)) {
+ broker = new ContextHubClientBroker(
+ mContext, mContextHubProxy, this, contextHubId, (short)id, clientCallback);
+ mHostEndPointIdToClientMap.put((short)id, broker);
+ mNextHostEndpointId = (id == MAX_CLIENT_ID) ? 0 : id + 1;
+ break;
+ }
+
+ id = (id == MAX_CLIENT_ID) ? 0 : id + 1;
+ }
+
+ return broker;
+ }
+
+ /**
+ * Broadcasts a message from a nanoapp to all clients attached to the associated hub.
+ *
+ * @param contextHubId the ID of the hub where the nanoapp sent the message from
+ * @param message the message send by a nanoapp
+ */
+ private void broadcastMessage(int contextHubId, NanoAppMessage message) {
+ forEachClientOfHub(contextHubId, client -> client.sendMessageToClient(message));
+ }
+
+ /**
+ * Runs a command for each client that is attached to a hub with the given ID.
+ *
+ * @param contextHubId the ID of the hub
+ * @param callback the command to invoke for the client
+ */
+ private void forEachClientOfHub(int contextHubId, Consumer<ContextHubClientBroker> callback) {
+ for (ContextHubClientBroker broker : mHostEndPointIdToClientMap.values()) {
+ if (broker.getAttachedContextHubId() == contextHubId) {
+ callback.accept(broker);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/ContextHubService.java b/services/core/java/com/android/server/location/ContextHubService.java
index da481a8..4525a49 100644
--- a/services/core/java/com/android/server/location/ContextHubService.java
+++ b/services/core/java/com/android/server/location/ContextHubService.java
@@ -16,12 +16,10 @@
package com.android.server.location;
-import android.Manifest;
import android.content.Context;
import android.hardware.contexthub.V1_0.AsyncEventType;
import android.hardware.contexthub.V1_0.ContextHub;
import android.hardware.contexthub.V1_0.ContextHubMsg;
-import android.hardware.contexthub.V1_0.HostEndPoint;
import android.hardware.contexthub.V1_0.HubAppInfo;
import android.hardware.contexthub.V1_0.IContexthub;
import android.hardware.contexthub.V1_0.IContexthubCallback;
@@ -29,13 +27,17 @@
import android.hardware.contexthub.V1_0.TransactionResult;
import android.hardware.location.ContextHubInfo;
import android.hardware.location.ContextHubMessage;
+import android.hardware.location.ContextHubTransaction;
import android.hardware.location.IContextHubCallback;
+import android.hardware.location.IContextHubClient;
+import android.hardware.location.IContextHubClientCallback;
import android.hardware.location.IContextHubService;
import android.hardware.location.IContextHubTransactionCallback;
import android.hardware.location.NanoApp;
import android.hardware.location.NanoAppBinary;
import android.hardware.location.NanoAppFilter;
import android.hardware.location.NanoAppInstanceInfo;
+import android.hardware.location.NanoAppMessage;
import android.hardware.location.NanoAppState;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -49,7 +51,9 @@
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentHashMap;
@@ -58,9 +62,6 @@
*/
public class ContextHubService extends IContextHubService.Stub {
private static final String TAG = "ContextHubService";
- private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
- private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
- + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
/*
* Constants for the type of transaction that is defined by ContextHubService.
@@ -104,6 +105,12 @@
// The manager for transaction queue
private final ContextHubTransactionManager mTransactionManager;
+ // The manager for sending messages to/from clients
+ private final ContextHubClientManager mClientManager;
+
+ // The default client for old API clients
+ private final Map<Integer, IContextHubClient> mDefaultClientMap;
+
/**
* Class extending the callback to register with a Context Hub.
*/
@@ -146,21 +153,34 @@
mContextHubProxy = getContextHubProxy();
if (mContextHubProxy == null) {
mTransactionManager = null;
+ mClientManager = null;
+ mDefaultClientMap = Collections.EMPTY_MAP;
mContextHubInfo = new ContextHubInfo[0];
return;
}
- mTransactionManager = new ContextHubTransactionManager(mContextHubProxy);
+ mClientManager = new ContextHubClientManager(mContext, mContextHubProxy);
+ mTransactionManager = new ContextHubTransactionManager(mContextHubProxy, mClientManager);
List<ContextHub> hubList;
try {
hubList = mContextHubProxy.getHubs();
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException while getting Context Hub info");
+ Log.e(TAG, "RemoteException while getting Context Hub info", e);
hubList = Collections.emptyList();
}
mContextHubInfo = ContextHubServiceUtil.createContextHubInfoArray(hubList);
+ HashMap<Integer, IContextHubClient> defaultClientMap = new HashMap<>();
+ for (ContextHubInfo contextHubInfo : mContextHubInfo) {
+ int contextHubId = contextHubInfo.getId();
+
+ IContextHubClient client = mClientManager.registerClient(
+ createDefaultClientCallback(contextHubId), contextHubId);
+ defaultClientMap.put(contextHubId, client);
+ }
+ mDefaultClientMap = Collections.unmodifiableMap(defaultClientMap);
+
for (ContextHubInfo contextHubInfo : mContextHubInfo) {
int contextHubId = contextHubInfo.getId();
try {
@@ -168,7 +188,7 @@
contextHubId, new ContextHubServiceCallback(contextHubId));
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while registering service callback for hub (ID = "
- + contextHubId + ")");
+ + contextHubId + ")", e);
}
}
@@ -185,6 +205,53 @@
}
/**
+ * Creates a default client callback for old API clients.
+ *
+ * @param contextHubId the ID of the hub to attach this client to
+ * @return the internal callback interface
+ */
+ private IContextHubClientCallback createDefaultClientCallback(int contextHubId) {
+ return new IContextHubClientCallback.Stub() {
+ @Override
+ public void onMessageFromNanoApp(NanoAppMessage message) {
+ int nanoAppInstanceId =
+ mNanoAppIdToInstanceMap.containsKey(message.getNanoAppId()) ?
+ mNanoAppIdToInstanceMap.get(message.getNanoAppId()) : -1;
+
+ onMessageReceiptOldApi(
+ message.getMessageType(), contextHubId, nanoAppInstanceId,
+ message.getMessageBody());
+ }
+
+ @Override
+ public void onHubReset() {
+ byte[] data = {TransactionResult.SUCCESS};
+ onMessageReceiptOldApi(MSG_HUB_RESET, contextHubId, OS_APP_INSTANCE, data);
+ }
+
+ @Override
+ public void onNanoAppAborted(long nanoAppId, int abortCode) {
+ }
+
+ @Override
+ public void onNanoAppLoaded(long nanoAppId) {
+ }
+
+ @Override
+ public void onNanoAppUnloaded(long nanoAppId) {
+ }
+
+ @Override
+ public void onNanoAppEnabled(long nanoAppId) {
+ }
+
+ @Override
+ public void onNanoAppDisabled(long nanoAppId) {
+ }
+ };
+ }
+
+ /**
* @return the IContexthub proxy interface
*/
private IContexthub getContextHubProxy() {
@@ -192,7 +259,7 @@
try {
proxy = IContexthub.getService(true /* retry */);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException while attaching to Context Hub HAL proxy");
+ Log.e(TAG, "RemoteException while attaching to Context Hub HAL proxy", e);
} catch (NoSuchElementException e) {
Log.i(TAG, "Context Hub HAL service not found");
}
@@ -204,6 +271,7 @@
public int registerCallback(IContextHubCallback callback) throws RemoteException {
checkPermissions();
mCallbacksList.register(callback);
+
Log.d(TAG, "Added callback, total callbacks " +
mCallbacksList.getRegisteredCallbackCount());
return 0;
@@ -292,7 +360,7 @@
@Override
public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
byte[] data = {(byte) result};
- onMessageReceipt(MSG_QUERY_NANO_APPS, contextHubId, OS_APP_INSTANCE, data);
+ onMessageReceiptOldApi(MSG_QUERY_NANO_APPS, contextHubId, OS_APP_INSTANCE, data);
}
};
}
@@ -411,7 +479,11 @@
retArray[i] = foundInstances.get(i).intValue();
}
- Log.w(TAG, "Found " + retArray.length + " apps on hub handle " + hubHandle);
+ if (retArray.length == 0) {
+ Log.d(TAG, "No nanoapps found on hub ID " + hubHandle + " using NanoAppFilter: "
+ + filter);
+ }
+
return retArray;
}
@@ -449,41 +521,37 @@
return -1;
}
if (msg.getData() == null) {
- Log.w(TAG, "ContextHubMessage message body cannot be null");
+ Log.e(TAG, "ContextHubMessage message body cannot be null");
+ return -1;
+ }
+ if (!mDefaultClientMap.containsKey(hubHandle)) {
+ Log.e(TAG, "Hub with ID " + hubHandle + " does not exist");
return -1;
}
- int result;
+ boolean success = false;
if (nanoAppHandle == OS_APP_INSTANCE) {
if (msg.getMsgType() == MSG_QUERY_NANO_APPS) {
- result = queryNanoAppsInternal(hubHandle);
+ success = (queryNanoAppsInternal(hubHandle) == Result.OK);
} else {
Log.e(TAG, "Invalid OS message params of type " + msg.getMsgType());
- result = Result.BAD_PARAMS;
}
} else {
NanoAppInstanceInfo info = getNanoAppInstanceInfo(nanoAppHandle);
if (info != null) {
- ContextHubMsg hubMessage = new ContextHubMsg();
- hubMessage.appName = info.getAppId();
- hubMessage.msgType = msg.getMsgType();
- hubMessage.hostEndPoint = HostEndPoint.UNSPECIFIED;
- ContextHubServiceUtil.copyToByteArrayList(msg.getData(), hubMessage.msg);
+ NanoAppMessage message = NanoAppMessage.createMessageToNanoApp(
+ info.getAppId(), msg.getMsgType(), msg.getData());
- try {
- result = mContextHubProxy.sendMessageToHub(hubHandle, hubMessage);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to send nanoapp message - RemoteException");
- result = Result.UNKNOWN_FAILURE;
- }
+ IContextHubClient client = mDefaultClientMap.get(hubHandle);
+ success = (client.sendMessageToNanoApp(message) ==
+ ContextHubTransaction.TRANSACTION_SUCCESS);
} else {
Log.e(TAG, "Failed to send nanoapp message - nanoapp with instance ID "
+ nanoAppHandle + " does not exist.");
- result = Result.BAD_PARAMS;
}
}
- return (result == Result.OK ? 0 : -1);
+ return success ? 0 : -1;
}
/**
@@ -493,12 +561,7 @@
* @param message the message contents
*/
private void handleClientMessageCallback(int contextHubId, ContextHubMsg message) {
- // TODO(b/67734082): Send to new API clients
- byte[] data = ContextHubServiceUtil.createPrimitiveByteArray(message.msg);
-
- int nanoAppInstanceId = mNanoAppIdToInstanceMap.containsKey(message.appName) ?
- mNanoAppIdToInstanceMap.get(message.appName) : -1;
- onMessageReceipt(message.msgType, contextHubId, nanoAppInstanceId, data);
+ mClientManager.onMessageFromNanoApp(contextHubId, message);
}
/**
@@ -534,7 +597,7 @@
data[0] = (byte) result;
ByteBuffer.wrap(data, 1, 4).order(ByteOrder.nativeOrder()).putInt(instanceId);
- onMessageReceipt(MSG_LOAD_NANO_APP, contextHubId, OS_APP_INSTANCE, data);
+ onMessageReceiptOldApi(MSG_LOAD_NANO_APP, contextHubId, OS_APP_INSTANCE, data);
}
/**
@@ -552,7 +615,7 @@
byte[] data = new byte[1];
data[0] = (byte) result;
- onMessageReceipt(MSG_UNLOAD_NANO_APP, contextHubId, OS_APP_INSTANCE, data);
+ onMessageReceiptOldApi(MSG_UNLOAD_NANO_APP, contextHubId, OS_APP_INSTANCE, data);
}
/**
@@ -577,8 +640,7 @@
mTransactionManager.onHubReset();
queryNanoAppsInternal(contextHubId);
- byte[] data = {TransactionResult.SUCCESS};
- onMessageReceipt(MSG_HUB_RESET, contextHubId, OS_APP_INSTANCE, data);
+ mClientManager.onHubReset(contextHubId);
} else {
Log.i(TAG, "Received unknown hub event (hub ID = " + contextHubId + ", type = "
+ eventType + ")");
@@ -641,6 +703,45 @@
}
}
+ /**
+ * @param contextHubId the hub ID to validate
+ * @return {@code true} if the ID represents that of an available hub, {@code false} otherwise
+ */
+ private boolean isValidContextHubId(int contextHubId) {
+ for (ContextHubInfo hubInfo : mContextHubInfo) {
+ if (hubInfo.getId() == contextHubId) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Creates and registers a client at the service for the specified Context Hub.
+ *
+ * @param clientCallback the client interface to register with the service
+ * @param contextHubId the ID of the hub this client is attached to
+ * @return the generated client interface, null if registration was unsuccessful
+ *
+ * @throws IllegalArgumentException if contextHubId is not a valid ID
+ * @throws IllegalStateException if max number of clients have already registered
+ * @throws NullPointerException if clientCallback is null
+ */
+ @Override
+ public IContextHubClient createClient(
+ IContextHubClientCallback clientCallback, int contextHubId) throws RemoteException {
+ checkPermissions();
+ if (!isValidContextHubId(contextHubId)) {
+ throw new IllegalArgumentException("Invalid context hub ID " + contextHubId);
+ }
+ if (clientCallback == null) {
+ throw new NullPointerException("Cannot register client with null callback");
+ }
+
+ return mClientManager.registerClient(clientCallback, contextHubId);
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
@@ -664,10 +765,10 @@
}
private void checkPermissions() {
- mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
+ ContextHubServiceUtil.checkPermissions(mContext);
}
- private int onMessageReceipt(int msgType, int hubHandle, int appInstance, byte[] data) {
+ private int onMessageReceiptOldApi(int msgType, int hubHandle, int appInstance, byte[] data) {
if (data == null) {
return -1;
}
diff --git a/services/core/java/com/android/server/location/ContextHubServiceTransaction.java b/services/core/java/com/android/server/location/ContextHubServiceTransaction.java
index 66145bb..a543daf 100644
--- a/services/core/java/com/android/server/location/ContextHubServiceTransaction.java
+++ b/services/core/java/com/android/server/location/ContextHubServiceTransaction.java
@@ -54,18 +54,10 @@
abstract int onTransact();
/**
- * A function to invoke when a transaction times out.
- *
- * All instances of this class must implement this method by reporting the timeout to the
- * client.
- */
- /* package */
- abstract void onTimeout();
-
- /**
* A function to invoke when the transaction completes.
*
- * Only relevant for load, unload, enable, or disable transactions.
+ * For transactions with expected contents (such as a query), the class instance should
+ * implement the appropriate behavior (e.g. invoke onQueryResponse with an empty list).
*
* @param result the result of the transaction
*/
diff --git a/services/core/java/com/android/server/location/ContextHubServiceUtil.java b/services/core/java/com/android/server/location/ContextHubServiceUtil.java
index ddbaf86..6faeb72 100644
--- a/services/core/java/com/android/server/location/ContextHubServiceUtil.java
+++ b/services/core/java/com/android/server/location/ContextHubServiceUtil.java
@@ -16,11 +16,15 @@
package com.android.server.location;
+import android.Manifest;
+import android.content.Context;
import android.hardware.contexthub.V1_0.ContextHub;
import android.hardware.contexthub.V1_0.ContextHubMsg;
import android.hardware.contexthub.V1_0.HostEndPoint;
import android.hardware.contexthub.V1_0.HubAppInfo;
+import android.hardware.contexthub.V1_0.Result;
import android.hardware.location.ContextHubInfo;
+import android.hardware.location.ContextHubTransaction;
import android.hardware.location.NanoAppBinary;
import android.hardware.location.NanoAppMessage;
import android.hardware.location.NanoAppState;
@@ -34,6 +38,9 @@
*/
/* package */ class ContextHubServiceUtil {
private static final String TAG = "ContextHubServiceUtil";
+ private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
+ private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
+ + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
/**
* Creates a ContextHubInfo array from an ArrayList of HIDL ContextHub objects.
@@ -165,4 +172,40 @@
message.appName, message.msgType, messageArray,
message.hostEndPoint == HostEndPoint.BROADCAST);
}
+
+ /**
+ * Checks for location hardware permissions.
+ *
+ * @param context the context of the service
+ */
+ /* package */
+ static void checkPermissions(Context context) {
+ context.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
+ }
+
+ /**
+ * Helper function to convert from the HAL Result enum error code to the
+ * ContextHubTransaction.Result type.
+ *
+ * @param halResult the Result enum error code
+ * @return the ContextHubTransaction.Result equivalent
+ */
+ @ContextHubTransaction.Result
+ /* package */
+ static int toTransactionResult(int halResult) {
+ switch (halResult) {
+ case Result.OK:
+ return ContextHubTransaction.TRANSACTION_SUCCESS;
+ case Result.BAD_PARAMS:
+ return ContextHubTransaction.TRANSACTION_FAILED_BAD_PARAMS;
+ case Result.NOT_INIT:
+ return ContextHubTransaction.TRANSACTION_FAILED_UNINITIALIZED;
+ case Result.TRANSACTION_PENDING:
+ return ContextHubTransaction.TRANSACTION_FAILED_PENDING;
+ case Result.TRANSACTION_FAILED:
+ case Result.UNKNOWN_FAILURE:
+ default: /* fall through */
+ return ContextHubTransaction.TRANSACTION_FAILED_UNKNOWN;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/location/ContextHubTransactionManager.java b/services/core/java/com/android/server/location/ContextHubTransactionManager.java
index 898b76c..3fcc682 100644
--- a/services/core/java/com/android/server/location/ContextHubTransactionManager.java
+++ b/services/core/java/com/android/server/location/ContextHubTransactionManager.java
@@ -58,6 +58,11 @@
private final IContexthub mContextHubProxy;
/*
+ * The manager for all clients for the service.
+ */
+ private final ContextHubClientManager mClientManager;
+
+ /*
* A queue containing the current transactions
*/
private final ArrayDeque<ContextHubServiceTransaction> mTransactionQueue = new ArrayDeque<>();
@@ -73,8 +78,10 @@
private final ScheduledThreadPoolExecutor mTimeoutExecutor = new ScheduledThreadPoolExecutor(1);
private ScheduledFuture<?> mTimeoutFuture = null;
- /* package */ ContextHubTransactionManager(IContexthub contextHubProxy) {
+ /* package */ ContextHubTransactionManager(
+ IContexthub contextHubProxy, ContextHubClientManager clientManager) {
mContextHubProxy = contextHubProxy;
+ mClientManager = clientManager;
}
/**
@@ -99,22 +106,20 @@
contextHubId, hidlNanoAppBinary, this.getTransactionId());
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while trying to load nanoapp with ID 0x" +
- Long.toHexString(nanoAppBinary.getNanoAppId()));
+ Long.toHexString(nanoAppBinary.getNanoAppId()), e);
return Result.UNKNOWN_FAILURE;
}
}
@Override
- /* package */ void onTimeout() {
- onTransactionComplete(ContextHubTransaction.TRANSACTION_FAILED_TIMEOUT);
- }
-
- @Override
/* package */ void onTransactionComplete(int result) {
try {
onCompleteCallback.onTransactionComplete(result);
+ if (result == Result.OK) {
+ mClientManager.onNanoAppLoaded(contextHubId, nanoAppBinary.getNanoAppId());
+ }
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException while calling client onTransactionComplete");
+ Log.e(TAG, "RemoteException while calling client onTransactionComplete", e);
}
}
};
@@ -139,22 +144,20 @@
contextHubId, nanoAppId, this.getTransactionId());
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while trying to unload nanoapp with ID 0x" +
- Long.toHexString(nanoAppId));
+ Long.toHexString(nanoAppId), e);
return Result.UNKNOWN_FAILURE;
}
}
@Override
- /* package */ void onTimeout() {
- onTransactionComplete(ContextHubTransaction.TRANSACTION_FAILED_TIMEOUT);
- }
-
- @Override
/* package */ void onTransactionComplete(int result) {
try {
onCompleteCallback.onTransactionComplete(result);
+ if (result == Result.OK) {
+ mClientManager.onNanoAppUnloaded(contextHubId, nanoAppId);
+ }
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException while calling client onTransactionComplete");
+ Log.e(TAG, "RemoteException while calling client onTransactionComplete", e);
}
}
};
@@ -176,15 +179,14 @@
try {
return mContextHubProxy.queryApps(contextHubId);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException while trying to query for nanoapps");
+ Log.e(TAG, "RemoteException while trying to query for nanoapps", e);
return Result.UNKNOWN_FAILURE;
}
}
@Override
- /* package */ void onTimeout() {
- onQueryResponse(ContextHubTransaction.TRANSACTION_FAILED_TIMEOUT,
- Collections.emptyList());
+ /* package */ void onTransactionComplete(int result) {
+ onQueryResponse(result, Collections.emptyList());
}
@Override
@@ -192,7 +194,7 @@
try {
onCompleteCallback.onQueryResponse(result, nanoAppStateList);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException while calling client onQueryComplete");
+ Log.e(TAG, "RemoteException while calling client onQueryComplete", e);
}
}
};
@@ -320,7 +322,8 @@
synchronized (this) {
if (!transaction.isComplete()) {
Log.d(TAG, transaction + " timed out");
- transaction.onTimeout();
+ transaction.onTransactionComplete(
+ ContextHubTransaction.TRANSACTION_FAILED_TIMEOUT);
removeTransactionAndStartNext();
}
@@ -331,6 +334,8 @@
mTimeoutFuture = mTimeoutExecutor.schedule(onTimeoutFunc, timeoutSeconds,
TimeUnit.SECONDS);
} else {
+ transaction.onTransactionComplete(
+ ContextHubServiceUtil.toTransactionResult(result));
mTransactionQueue.remove();
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
new file mode 100644
index 0000000..2bd9cab
--- /dev/null
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -0,0 +1,514 @@
+/*
+ * 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.net;
+
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
+import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
+import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
+import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
+
+import android.app.ActivityManager;
+import android.net.NetworkPolicyManager;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.RingBuffer;
+import com.android.server.am.ProcessList;
+
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+
+public class NetworkPolicyLogger {
+ static final String TAG = "NetworkPolicy";
+
+ static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
+ static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE);
+
+ private static final int MAX_LOG_SIZE =
+ ActivityManager.isLowRamDeviceStatic() ? 20 : 50;
+ private static final int MAX_NETWORK_BLOCKED_LOG_SIZE =
+ ActivityManager.isLowRamDeviceStatic() ? 50 : 100;
+
+ private static final int EVENT_TYPE_GENERIC = 0;
+ private static final int EVENT_NETWORK_BLOCKED = 1;
+ private static final int EVENT_UID_STATE_CHANGED = 2;
+ private static final int EVENT_POLICIES_CHANGED = 3;
+ private static final int EVENT_METEREDNESS_CHANGED = 4;
+ private static final int EVENT_USER_STATE_REMOVED = 5;
+ private static final int EVENT_RESTRICT_BG_CHANGED = 6;
+ private static final int EVENT_DEVICE_IDLE_MODE_ENABLED = 7;
+ private static final int EVENT_APP_IDLE_STATE_CHANGED = 8;
+ private static final int EVENT_PAROLE_STATE_CHANGED = 9;
+ private static final int EVENT_TEMP_POWER_SAVE_WL_CHANGED = 10;
+ private static final int EVENT_UID_FIREWALL_RULE_CHANGED = 11;
+ private static final int EVENT_FIREWALL_CHAIN_ENABLED = 12;
+
+ static final int NTWK_BLOCKED_POWER = 0;
+ static final int NTWK_ALLOWED_NON_METERED = 1;
+ static final int NTWK_BLOCKED_BLACKLIST = 2;
+ static final int NTWK_ALLOWED_WHITELIST = 3;
+ static final int NTWK_ALLOWED_TMP_WHITELIST = 4;
+ static final int NTWK_BLOCKED_BG_RESTRICT = 5;
+ static final int NTWK_ALLOWED_DEFAULT = 6;
+
+ private final LogBuffer mNetworkBlockedBuffer = new LogBuffer(MAX_NETWORK_BLOCKED_LOG_SIZE);
+ private final LogBuffer mUidStateChangeBuffer = new LogBuffer(MAX_LOG_SIZE);
+ private final LogBuffer mEventsBuffer = new LogBuffer(MAX_LOG_SIZE);
+
+ private final Object mLock = new Object();
+
+ void networkBlocked(int uid, int reason) {
+ synchronized (mLock) {
+ if (LOGD) Slog.d(TAG, uid + " is " + getBlockedReason(reason));
+ mNetworkBlockedBuffer.networkBlocked(uid, reason);
+ }
+ }
+
+ void uidStateChanged(int uid, int procState, long procStateSeq) {
+ synchronized (mLock) {
+ if (LOGV) Slog.v(TAG,
+ uid + " state changed to " + procState + " with seq=" + procStateSeq);
+ mUidStateChangeBuffer.uidStateChanged(uid, procState, procStateSeq);
+ }
+ }
+
+ void event(String msg) {
+ synchronized (mLock) {
+ if (LOGV) Slog.v(TAG, msg);
+ mEventsBuffer.event(msg);
+ }
+ }
+
+ void uidPolicyChanged(int uid, int oldPolicy, int newPolicy) {
+ synchronized (mLock) {
+ if (LOGV) Slog.v(TAG, getPolicyChangedLog(uid, oldPolicy, newPolicy));
+ mEventsBuffer.uidPolicyChanged(uid, oldPolicy, newPolicy);
+ }
+ }
+
+ void meterednessChanged(int netId, boolean newMetered) {
+ synchronized (mLock) {
+ if (LOGD) Slog.d(TAG, getMeterednessChangedLog(netId, newMetered));
+ mEventsBuffer.meterednessChanged(netId, newMetered);
+ }
+ }
+
+ void removingUserState(int userId) {
+ synchronized (mLock) {
+ if (LOGD) Slog.d(TAG, getUserRemovedLog(userId));
+ mEventsBuffer.userRemoved(userId);
+ }
+ }
+
+ void restrictBackgroundChanged(boolean oldValue, boolean newValue) {
+ synchronized (mLock) {
+ if (LOGD) Slog.d(TAG,
+ getRestrictBackgroundChangedLog(oldValue, newValue));
+ mEventsBuffer.restrictBackgroundChanged(oldValue, newValue);
+ }
+ }
+
+ void deviceIdleModeEnabled(boolean enabled) {
+ synchronized (mLock) {
+ if (LOGD) Slog.d(TAG, getDeviceIdleModeEnabled(enabled));
+ mEventsBuffer.deviceIdleModeEnabled(enabled);
+ }
+ }
+
+ void appIdleStateChanged(int uid, boolean idle) {
+ synchronized (mLock) {
+ if (LOGD) Slog.d(TAG, getAppIdleChangedLog(uid, idle));
+ mEventsBuffer.appIdleStateChanged(uid, idle);
+ }
+ }
+
+ void paroleStateChanged(boolean paroleOn) {
+ synchronized (mLock) {
+ if (LOGD) Slog.d(TAG, getParoleStateChanged(paroleOn));
+ mEventsBuffer.paroleStateChanged(paroleOn);
+ }
+ }
+
+ void tempPowerSaveWlChanged(int appId, boolean added) {
+ synchronized (mLock) {
+ if (LOGV) Slog.v(TAG, getTempPowerSaveWlChangedLog(appId, added));
+ mEventsBuffer.tempPowerSaveWlChanged(appId, added);
+ }
+ }
+
+ void uidFirewallRuleChanged(int chain, int uid, int rule) {
+ synchronized (mLock) {
+ if (LOGV) Slog.v(TAG, getUidFirewallRuleChangedLog(chain, uid, rule));
+ mEventsBuffer.uidFirewallRuleChanged(chain, uid, rule);
+ }
+ }
+
+ void firewallChainEnabled(int chain, boolean enabled) {
+ synchronized (mLock) {
+ if (LOGD) Slog.d(TAG, getFirewallChainEnabledLog(chain, enabled));
+ mEventsBuffer.firewallChainEnabled(chain, enabled);
+ }
+ }
+
+ void firewallRulesChanged(int chain, int[] uids, int[] rules) {
+ synchronized (mLock) {
+ final String log = "Firewall rules changed for " + getFirewallChainName(chain)
+ + "; uids=" + Arrays.toString(uids) + "; rules=" + Arrays.toString(rules);
+ if (LOGD) Slog.d(TAG, log);
+ mEventsBuffer.event(log);
+ }
+ }
+
+ void dumpLogs(IndentingPrintWriter pw) {
+ synchronized (mLock) {
+ pw.println();
+ pw.println("mEventLogs (most recent first):");
+ pw.increaseIndent();
+ mEventsBuffer.reverseDump(pw);
+ pw.decreaseIndent();
+
+ pw.println();
+ pw.println("mNetworkBlockedLogs (most recent first):");
+ pw.increaseIndent();
+ mNetworkBlockedBuffer.reverseDump(pw);
+ pw.decreaseIndent();
+
+ pw.println();
+ pw.println("mUidStateChangeLogs (most recent first):");
+ pw.increaseIndent();
+ mUidStateChangeBuffer.reverseDump(pw);
+ pw.decreaseIndent();
+ }
+ }
+
+ private static String getBlockedReason(int reason) {
+ switch (reason) {
+ case NTWK_BLOCKED_POWER:
+ return "blocked by power restrictions";
+ case NTWK_ALLOWED_NON_METERED:
+ return "allowed on unmetered network";
+ case NTWK_BLOCKED_BLACKLIST:
+ return "blacklisted on metered network";
+ case NTWK_ALLOWED_WHITELIST:
+ return "whitelisted on metered network";
+ case NTWK_ALLOWED_TMP_WHITELIST:
+ return "temporary whitelisted on metered network";
+ case NTWK_BLOCKED_BG_RESTRICT:
+ return "blocked when background is restricted";
+ case NTWK_ALLOWED_DEFAULT:
+ return "allowed by default";
+ default:
+ return String.valueOf(reason);
+ }
+ }
+
+ private static String getPolicyChangedLog(int uid, int oldPolicy, int newPolicy) {
+ return "Policy for " + uid + " changed from "
+ + NetworkPolicyManager.uidPoliciesToString(oldPolicy) + " to "
+ + NetworkPolicyManager.uidPoliciesToString(newPolicy);
+ }
+
+ private static String getMeterednessChangedLog(int netId, boolean newMetered) {
+ return "Meteredness of netId=" + netId + " changed to " + newMetered;
+ }
+
+ private static String getUserRemovedLog(int userId) {
+ return "Remove state for u" + userId;
+ }
+
+ private static String getRestrictBackgroundChangedLog(boolean oldValue, boolean newValue) {
+ return "Changed restrictBackground: " + oldValue + "->" + newValue;
+ }
+
+ private static String getDeviceIdleModeEnabled(boolean enabled) {
+ return "DeviceIdleMode enabled: " + enabled;
+ }
+
+ private static String getAppIdleChangedLog(int uid, boolean idle) {
+ return "App idle state of uid " + uid + ": " + idle;
+ }
+
+ private static String getParoleStateChanged(boolean paroleOn) {
+ return "Parole state: " + paroleOn;
+ }
+
+ private static String getTempPowerSaveWlChangedLog(int appId, boolean added) {
+ return "temp-power-save whitelist for " + appId + " changed to: " + added;
+ }
+
+ private static String getUidFirewallRuleChangedLog(int chain, int uid, int rule) {
+ return String.format("Firewall rule changed: %d-%s-%s",
+ uid, getFirewallChainName(chain), getFirewallRuleName(rule));
+ }
+
+ private static String getFirewallChainEnabledLog(int chain, boolean enabled) {
+ return "Firewall chain " + getFirewallChainName(chain) + " state: " + enabled;
+ }
+
+ private static String getFirewallChainName(int chain) {
+ switch (chain) {
+ case FIREWALL_CHAIN_DOZABLE:
+ return FIREWALL_CHAIN_NAME_DOZABLE;
+ case FIREWALL_CHAIN_STANDBY:
+ return FIREWALL_CHAIN_NAME_STANDBY;
+ case FIREWALL_CHAIN_POWERSAVE:
+ return FIREWALL_CHAIN_NAME_POWERSAVE;
+ default:
+ return String.valueOf(chain);
+ }
+ }
+
+ private static String getFirewallRuleName(int rule) {
+ switch (rule) {
+ case FIREWALL_RULE_DEFAULT:
+ return "default";
+ case FIREWALL_RULE_ALLOW:
+ return "allow";
+ case FIREWALL_RULE_DENY:
+ return "deny";
+ default:
+ return String.valueOf(rule);
+ }
+ }
+
+ private final static class LogBuffer extends RingBuffer<Data> {
+ private static final SimpleDateFormat sFormatter
+ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss:SSS");
+ private static final Date sDate = new Date();
+
+ public LogBuffer(int capacity) {
+ super(Data.class, capacity);
+ }
+
+ public void uidStateChanged(int uid, int procState, long procStateSeq) {
+ final Data data = getNextSlot();
+ if (data == null) return;
+
+ data.reset();
+ data.type = EVENT_UID_STATE_CHANGED;
+ data.ifield1 = uid;
+ data.ifield2 = procState;
+ data.lfield1 = procStateSeq;
+ data.timeStamp = System.currentTimeMillis();
+ }
+
+ public void event(String msg) {
+ final Data data = getNextSlot();
+ if (data == null) return;
+
+ data.reset();
+ data.type = EVENT_TYPE_GENERIC;
+ data.sfield1 = msg;
+ data.timeStamp = System.currentTimeMillis();
+ }
+
+ public void networkBlocked(int uid, int reason) {
+ final Data data = getNextSlot();
+ if (data == null) return;
+
+ data.reset();
+ data.type = EVENT_NETWORK_BLOCKED;
+ data.ifield1 = uid;
+ data.ifield2 = reason;
+ data.timeStamp = System.currentTimeMillis();
+ }
+
+ public void uidPolicyChanged(int uid, int oldPolicy, int newPolicy) {
+ final Data data = getNextSlot();
+ if (data == null) return;
+
+ data.reset();
+ data.type = EVENT_POLICIES_CHANGED;
+ data.ifield1 = uid;
+ data.ifield2 = oldPolicy;
+ data.ifield3 = newPolicy;
+ data.timeStamp = System.currentTimeMillis();
+ }
+
+ public void meterednessChanged(int netId, boolean newMetered) {
+ final Data data = getNextSlot();
+ if (data == null) return;
+
+ data.reset();
+ data.type = EVENT_METEREDNESS_CHANGED;
+ data.ifield1 = netId;
+ data.bfield1 = newMetered;
+ data.timeStamp = System.currentTimeMillis();
+ }
+
+ public void userRemoved(int userId) {
+ final Data data = getNextSlot();
+ if (data == null) return;
+
+ data.reset();
+ data.type = EVENT_USER_STATE_REMOVED;
+ data.ifield1 = userId;
+ data.timeStamp = System.currentTimeMillis();
+ }
+
+ public void restrictBackgroundChanged(boolean oldValue, boolean newValue) {
+ final Data data = getNextSlot();
+ if (data == null) return;
+
+ data.reset();
+ data.type = EVENT_RESTRICT_BG_CHANGED;
+ data.bfield1 = oldValue;
+ data.bfield2 = newValue;
+ data.timeStamp = System.currentTimeMillis();
+ }
+
+ public void deviceIdleModeEnabled(boolean enabled) {
+ final Data data = getNextSlot();
+ if (data == null) return;
+
+ data.reset();
+ data.type = EVENT_DEVICE_IDLE_MODE_ENABLED;
+ data.bfield1 = enabled;
+ data.timeStamp = System.currentTimeMillis();
+ }
+
+ public void appIdleStateChanged(int uid, boolean idle) {
+ final Data data = getNextSlot();
+ if (data == null) return;
+
+ data.reset();
+ data.type = EVENT_APP_IDLE_STATE_CHANGED;
+ data.ifield1 = uid;
+ data.bfield1 = idle;
+ data.timeStamp = System.currentTimeMillis();
+ }
+
+ public void paroleStateChanged(boolean paroleOn) {
+ final Data data = getNextSlot();
+ if (data == null) return;
+
+ data.reset();
+ data.type = EVENT_PAROLE_STATE_CHANGED;
+ data.bfield1 = paroleOn;
+ data.timeStamp = System.currentTimeMillis();
+ }
+
+ public void tempPowerSaveWlChanged(int appId, boolean added) {
+ final Data data = getNextSlot();
+ if (data == null) return;
+
+ data.reset();
+ data.type = EVENT_TEMP_POWER_SAVE_WL_CHANGED;
+ data.ifield1 = appId;
+ data.bfield1 = added;
+ data.timeStamp = System.currentTimeMillis();
+ }
+
+ public void uidFirewallRuleChanged(int chain, int uid, int rule) {
+ final Data data = getNextSlot();
+ if (data == null) return;
+
+ data.reset();
+ data.type = EVENT_UID_FIREWALL_RULE_CHANGED;
+ data.ifield1 = chain;
+ data.ifield2 = uid;
+ data.ifield3 = rule;
+ data.timeStamp = System.currentTimeMillis();
+ }
+
+ public void firewallChainEnabled(int chain, boolean enabled) {
+ final Data data = getNextSlot();
+ if (data == null) return;
+
+ data.reset();
+ data.type = EVENT_FIREWALL_CHAIN_ENABLED;
+ data.ifield1 = chain;
+ data.bfield1 = enabled;
+ data.timeStamp = System.currentTimeMillis();
+ }
+
+ public void reverseDump(IndentingPrintWriter pw) {
+ final Data[] allData = toArray();
+ for (int i = allData.length - 1; i >= 0; --i) {
+ if (allData[i] == null) {
+ pw.println("NULL");
+ continue;
+ }
+ pw.print(formatDate(allData[i].timeStamp));
+ pw.print(" - ");
+ pw.println(getContent(allData[i]));
+ }
+ }
+
+ public String getContent(Data data) {
+ switch (data.type) {
+ case EVENT_TYPE_GENERIC:
+ return data.sfield1;
+ case EVENT_NETWORK_BLOCKED:
+ return data.ifield1 + "-" + getBlockedReason(data.ifield2);
+ case EVENT_UID_STATE_CHANGED:
+ return data.ifield1 + "-" + ProcessList.makeProcStateString(data.ifield2)
+ + "-" + data.lfield1;
+ case EVENT_POLICIES_CHANGED:
+ return getPolicyChangedLog(data.ifield1, data.ifield2, data.ifield3);
+ case EVENT_METEREDNESS_CHANGED:
+ return getMeterednessChangedLog(data.ifield1, data.bfield1);
+ case EVENT_USER_STATE_REMOVED:
+ return getUserRemovedLog(data.ifield1);
+ case EVENT_RESTRICT_BG_CHANGED:
+ return getRestrictBackgroundChangedLog(data.bfield1, data.bfield2);
+ case EVENT_DEVICE_IDLE_MODE_ENABLED:
+ return getDeviceIdleModeEnabled(data.bfield1);
+ case EVENT_APP_IDLE_STATE_CHANGED:
+ return getAppIdleChangedLog(data.ifield1, data.bfield1);
+ case EVENT_PAROLE_STATE_CHANGED:
+ return getParoleStateChanged(data.bfield1);
+ case EVENT_TEMP_POWER_SAVE_WL_CHANGED:
+ return getTempPowerSaveWlChangedLog(data.ifield1, data.bfield1);
+ case EVENT_UID_FIREWALL_RULE_CHANGED:
+ return getUidFirewallRuleChangedLog(data.ifield1, data.ifield2, data.ifield3);
+ case EVENT_FIREWALL_CHAIN_ENABLED:
+ return getFirewallChainEnabledLog(data.ifield1, data.bfield1);
+ default:
+ return String.valueOf(data.type);
+ }
+ }
+
+ private String formatDate(long millis) {
+ sDate.setTime(millis);
+ return sFormatter.format(sDate);
+ }
+ }
+
+ public final static class Data {
+ int type;
+ long timeStamp;
+
+ int ifield1;
+ int ifield2;
+ int ifield3;
+ long lfield1;
+ boolean bfield1;
+ boolean bfield2;
+ String sfield1;
+
+ public void reset(){
+ sfield1 = null;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 3fa3cd4..fdfe241 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -82,6 +82,13 @@
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.internal.util.XmlUtils.writeStringAttribute;
import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
+import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_DEFAULT;
+import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_NON_METERED;
+import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_TMP_WHITELIST;
+import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_WHITELIST;
+import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_BG_RESTRICT;
+import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_BLACKLIST;
+import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_POWER;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -248,9 +255,9 @@
* </ul>
*/
public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
- static final String TAG = "NetworkPolicy";
- private static final boolean LOGD = false;
- private static final boolean LOGV = false;
+ static final String TAG = NetworkPolicyLogger.TAG;
+ private static final boolean LOGD = NetworkPolicyLogger.LOGD;
+ private static final boolean LOGV = NetworkPolicyLogger.LOGV;
private static final int VERSION_INIT = 1;
private static final int VERSION_ADDED_SNOOZE = 2;
@@ -265,13 +272,6 @@
private static final int VERSION_ADDED_CYCLE = 11;
private static final int VERSION_LATEST = VERSION_ADDED_CYCLE;
- /**
- * Max items written to {@link #ProcStateSeqHistory}.
- */
- @VisibleForTesting
- public static final int MAX_PROC_STATE_SEQ_HISTORY =
- ActivityManager.isLowRamDeviceStatic() ? 50 : 200;
-
@VisibleForTesting
public static final int TYPE_WARNING = SystemMessage.NOTE_NET_WARNING;
@VisibleForTesting
@@ -471,13 +471,7 @@
private ActivityManagerInternal mActivityManagerInternal;
- /**
- * This is used for debugging purposes. Whenever the IUidObserver.onUidStateChanged is called,
- * the uid and procStateSeq will be written to this and will be printed as part of dump.
- */
- @VisibleForTesting
- public ProcStateSeqHistory mObservedHistory
- = new ProcStateSeqHistory(MAX_PROC_STATE_SEQ_HISTORY);
+ private final NetworkPolicyLogger mLogger = new NetworkPolicyLogger();
// TODO: keep whitelist of system-critical services that should never have
// rules enforced, such as system, phone, and radio UIDs.
@@ -966,6 +960,7 @@
.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
if ((oldMetered != newMetered) || mNetworkMetered.indexOfKey(network.netId) < 0) {
+ mLogger.meterednessChanged(network.netId, newMetered);
mNetworkMetered.put(network.netId, newMetered);
updateNetworkRulesNL();
}
@@ -2148,6 +2143,7 @@
final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
if (oldPolicy != policy) {
setUidPolicyUncheckedUL(uid, oldPolicy, policy, true);
+ mLogger.uidPolicyChanged(uid, oldPolicy, policy);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -2168,6 +2164,7 @@
policy |= oldPolicy;
if (oldPolicy != policy) {
setUidPolicyUncheckedUL(uid, oldPolicy, policy, true);
+ mLogger.uidPolicyChanged(uid, oldPolicy, policy);
}
}
}
@@ -2185,6 +2182,7 @@
policy = oldPolicy & ~policy;
if (oldPolicy != policy) {
setUidPolicyUncheckedUL(uid, oldPolicy, policy, true);
+ mLogger.uidPolicyChanged(uid, oldPolicy, policy);
}
}
}
@@ -2264,7 +2262,7 @@
*/
boolean removeUserStateUL(int userId, boolean writePolicy) {
- if (LOGV) Slog.v(TAG, "removeUserStateUL()");
+ mLogger.removingUserState(userId);
boolean changed = false;
// Remove entries from revoked default restricted background UID whitelist
@@ -2429,7 +2427,6 @@
@Override
public void onTetheringChanged(String iface, boolean tethering) {
// No need to enforce permission because setRestrictBackground() will do it.
- if (LOGD) Log.d(TAG, "onTetherStateChanged(" + iface + ", " + tethering + ")");
synchronized (mUidRulesFirstLock) {
if (mRestrictBackground && tethering) {
Log.d(TAG, "Tethering on (" + iface +"); disable Data Saver");
@@ -2486,6 +2483,7 @@
}
sendRestrictBackgroundChangedMsg();
+ mLogger.restrictBackgroundChanged(oldRestrictBackground, mRestrictBackground);
if (mRestrictBackgroundPowerState.globalBatterySaverEnabled) {
mRestrictBackgroundChangedInBsm = true;
@@ -2551,6 +2549,7 @@
return;
}
mDeviceIdleMode = enabled;
+ mLogger.deviceIdleModeEnabled(enabled);
if (mSystemReady) {
// Device idle change means we need to rebuild rules for all
// known apps, so do a global refresh.
@@ -2964,10 +2963,7 @@
}
fout.decreaseIndent();
- fout.println("Observed uid state changes:");
- fout.increaseIndent();
- mObservedHistory.dumpUL(fout);
- fout.decreaseIndent();
+ mLogger.dumpLogs(fout);
}
}
}
@@ -3750,8 +3746,8 @@
try {
final int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
- if (LOGV) Log.v(TAG, "onAppIdleStateChanged(): uid=" + uid + ", idle=" + idle);
synchronized (mUidRulesFirstLock) {
+ mLogger.appIdleStateChanged(uid, idle);
updateRuleForAppIdleUL(uid);
updateRulesForPowerRestrictionsUL(uid);
}
@@ -3762,6 +3758,7 @@
@Override
public void onParoleStateChanged(boolean isParoleOn) {
synchronized (mUidRulesFirstLock) {
+ mLogger.paroleStateChanged(isParoleOn);
updateRulesForAppIdleParoleUL();
}
}
@@ -3947,7 +3944,7 @@
synchronized (mUidRulesFirstLock) {
// We received a uid state change callback, add it to the history so that it
// will be useful for debugging.
- mObservedHistory.addProcStateSeqUL(uid, procStateSeq);
+ mLogger.uidStateChanged(uid, procState, procStateSeq);
// Now update the network policy rules as per the updated uid state.
updateUidStateUL(uid, procState);
// Updating the network rules is done, so notify AMS about this.
@@ -4081,6 +4078,7 @@
rules[index] = uidRules.valueAt(index);
}
mNetworkManager.setFirewallUidRules(chain, uids, rules);
+ mLogger.firewallRulesChanged(chain, uids, rules);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting firewall uid rules", e);
} catch (RemoteException e) {
@@ -4107,6 +4105,7 @@
try {
mNetworkManager.setFirewallUidRule(chain, uid, rule);
+ mLogger.uidFirewallRuleChanged(chain, uid, rule);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting firewall uid rules", e);
} catch (RemoteException e) {
@@ -4129,6 +4128,7 @@
mFirewallChainStates.put(chain, enable);
try {
mNetworkManager.setFirewallChainEnabled(chain, enable);
+ mLogger.firewallChainEnabled(chain, enable);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem enable firewall chain", e);
} catch (RemoteException e) {
@@ -4305,30 +4305,30 @@
isBackgroundRestricted = mRestrictBackground;
}
if (hasRule(uidRules, RULE_REJECT_ALL)) {
- if (LOGV) logUidStatus(uid, "blocked by power restrictions");
+ mLogger.networkBlocked(uid, NTWK_BLOCKED_POWER);
return true;
}
if (!isNetworkMetered) {
- if (LOGV) logUidStatus(uid, "allowed on unmetered network");
+ mLogger.networkBlocked(uid, NTWK_ALLOWED_NON_METERED);
return false;
}
if (hasRule(uidRules, RULE_REJECT_METERED)) {
- if (LOGV) logUidStatus(uid, "blacklisted on metered network");
+ mLogger.networkBlocked(uid, NTWK_BLOCKED_BLACKLIST);
return true;
}
if (hasRule(uidRules, RULE_ALLOW_METERED)) {
- if (LOGV) logUidStatus(uid, "whitelisted on metered network");
+ mLogger.networkBlocked(uid, NTWK_ALLOWED_WHITELIST);
return false;
}
if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) {
- if (LOGV) logUidStatus(uid, "temporary whitelisted on metered network");
+ mLogger.networkBlocked(uid, NTWK_ALLOWED_TMP_WHITELIST);
return false;
}
if (isBackgroundRestricted) {
- if (LOGV) logUidStatus(uid, "blocked when background is restricted");
+ mLogger.networkBlocked(uid, NTWK_BLOCKED_BG_RESTRICT);
return true;
}
- if (LOGV) logUidStatus(uid, "allowed by default");
+ mLogger.networkBlocked(uid, NTWK_ALLOWED_DEFAULT);
return false;
}
@@ -4379,6 +4379,7 @@
@Override
public void onTempPowerSaveWhitelistChange(int appId, boolean added) {
synchronized (mUidRulesFirstLock) {
+ mLogger.tempPowerSaveWlChanged(appId, added);
if (added) {
mPowerSaveTempWhitelistAppIds.put(appId, true);
} else {
@@ -4393,80 +4394,6 @@
return (uidRules & rule) != 0;
}
- private static void logUidStatus(int uid, String descr) {
- Slog.d(TAG, String.format("uid %d is %s", uid, descr));
- }
-
- /**
- * This class is used for storing and dumping the last {@link #MAX_PROC_STATE_SEQ_HISTORY}
- * (uid, procStateSeq) pairs.
- */
- @VisibleForTesting
- public static final class ProcStateSeqHistory {
- private static final int INVALID_UID = -1;
-
- /**
- * Denotes maximum number of items this history can hold.
- */
- private final int mMaxCapacity;
- /**
- * Used for storing the uid information.
- */
- private final int[] mUids;
- /**
- * Used for storing the sequence numbers associated with {@link #mUids}.
- */
- private final long[] mProcStateSeqs;
- /**
- * Points to the next available slot for writing (uid, procStateSeq) pair.
- */
- private int mHistoryNext;
-
- public ProcStateSeqHistory(int maxCapacity) {
- mMaxCapacity = maxCapacity;
- mUids = new int[mMaxCapacity];
- Arrays.fill(mUids, INVALID_UID);
- mProcStateSeqs = new long[mMaxCapacity];
- }
-
- @GuardedBy("mUidRulesFirstLock")
- public void addProcStateSeqUL(int uid, long procStateSeq) {
- mUids[mHistoryNext] = uid;
- mProcStateSeqs[mHistoryNext] = procStateSeq;
- mHistoryNext = increaseNext(mHistoryNext, 1);
- }
-
- @GuardedBy("mUidRulesFirstLock")
- public void dumpUL(IndentingPrintWriter fout) {
- if (mUids[0] == INVALID_UID) {
- fout.println("NONE");
- return;
- }
- int index = mHistoryNext;
- do {
- index = increaseNext(index, -1);
- if (mUids[index] == INVALID_UID) {
- break;
- }
- fout.println(getString(mUids[index], mProcStateSeqs[index]));
- } while (index != mHistoryNext);
- }
-
- public static String getString(int uid, long procStateSeq) {
- return "UID=" + uid + " Seq=" + procStateSeq;
- }
-
- private int increaseNext(int next, int increment) {
- next += increment;
- if (next >= mMaxCapacity) {
- next = 0;
- } else if (next < 0) {
- next = mMaxCapacity - 1;
- }
- return next;
- }
- }
-
private class NotificationId {
private final String mTag;
private final int mId;
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 019c7c2..7d64aed4 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -39,8 +39,10 @@
import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.Build;
+import android.os.Handler;
import android.os.IBinder;
import android.os.IInterface;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -86,6 +88,7 @@
protected final String TAG = getClass().getSimpleName();
protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final int ON_BINDING_DIED_REBIND_DELAY_MS = 10000;
protected static final String ENABLED_SERVICES_SEPARATOR = ":";
/**
@@ -105,12 +108,15 @@
private final IPackageManager mPm;
private final UserManager mUm;
private final Config mConfig;
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
// contains connections to all connected services, including app services
// and system services
private final ArrayList<ManagedServiceInfo> mServices = new ArrayList<>();
// things that will be put into mServices as soon as they're ready
private final ArrayList<String> mServicesBinding = new ArrayList<>();
+ private final ArraySet<String> mServicesRebinding = new ArraySet<>();
+
// lists the component names of all enabled (and therefore potentially connected)
// app services for current profiles.
private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles
@@ -890,6 +896,7 @@
final String servicesBindingTag = name.toString() + "/" + userid;
if (mServicesBinding.contains(servicesBindingTag)) {
+ Slog.v(TAG, "Not registering " + name + " as bind is already in progress");
// stop registering this thing already! we're working on it
return;
}
@@ -938,6 +945,7 @@
boolean added = false;
ManagedServiceInfo info = null;
synchronized (mMutex) {
+ mServicesRebinding.remove(servicesBindingTag);
mServicesBinding.remove(servicesBindingTag);
try {
mService = asInterface(binder);
@@ -959,6 +967,27 @@
mServicesBinding.remove(servicesBindingTag);
Slog.v(TAG, getCaption() + " connection lost: " + name);
}
+
+ @Override
+ public void onBindingDied(ComponentName name) {
+ Slog.w(TAG, getCaption() + " binding died: " + name);
+ synchronized (mMutex) {
+ mServicesBinding.remove(servicesBindingTag);
+ mContext.unbindService(this);
+ if (!mServicesRebinding.contains(servicesBindingTag)) {
+ mServicesRebinding.add(servicesBindingTag);
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ registerService(name, userid);
+ }
+ }, ON_BINDING_DIED_REBIND_DELAY_MS);
+ } else {
+ Slog.v(TAG, getCaption() + " not rebinding as "
+ + "a previous rebind attempt was made: " + name);
+ }
+ }
+ }
};
if (!mContext.bindServiceAsUser(intent,
serviceConnection,
diff --git a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
index 50a51b2..ba7fe78 100644
--- a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
+++ b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
@@ -29,21 +29,22 @@
import android.provider.Settings;
import android.service.notification.Condition;
import android.service.notification.IConditionProvider;
+import android.service.notification.ScheduleCalendar;
import android.service.notification.ZenModeConfig;
-import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.notification.NotificationManagerService.DumpFilter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
-import java.util.TimeZone;
/**
* Built-in zen condition provider for daily scheduled time-based conditions.
@@ -62,10 +63,9 @@
private static final String SEPARATOR = ";";
private static final String SCP_SETTING = "snoozed_schedule_condition_provider";
-
private final Context mContext = this;
private final ArrayMap<Uri, ScheduleCalendar> mSubscriptions = new ArrayMap<>();
- private ArraySet<Uri> mSnoozed = new ArraySet<>();
+ private ArraySet<Uri> mSnoozedForAlarm = new ArraySet<>();
private AlarmManager mAlarmManager;
private boolean mConnected;
@@ -102,7 +102,7 @@
pw.println(mSubscriptions.get(conditionId).toString());
}
}
- pw.println(" snoozed due to alarm: " + TextUtils.join(SEPARATOR, mSnoozed));
+ pw.println(" snoozed due to alarm: " + TextUtils.join(SEPARATOR, mSnoozedForAlarm));
dumpUpcomingTime(pw, "mNextAlarmTime", mNextAlarmTime, now);
}
@@ -129,11 +129,11 @@
public void onSubscribe(Uri conditionId) {
if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId);
if (!ZenModeConfig.isValidScheduleConditionId(conditionId)) {
- notifyCondition(createCondition(conditionId, Condition.STATE_FALSE, "badCondition"));
+ notifyCondition(createCondition(conditionId, Condition.STATE_ERROR, "invalidId"));
return;
}
synchronized (mSubscriptions) {
- mSubscriptions.put(conditionId, toScheduleCalendar(conditionId));
+ mSubscriptions.put(conditionId, ZenModeConfig.toScheduleCalendar(conditionId));
}
evaluateSubscriptions();
}
@@ -169,32 +169,11 @@
synchronized (mSubscriptions) {
setRegistered(!mSubscriptions.isEmpty());
for (Uri conditionId : mSubscriptions.keySet()) {
- final ScheduleCalendar cal = mSubscriptions.get(conditionId);
- if (cal != null && cal.isInSchedule(now)) {
- if (conditionSnoozed(conditionId) || cal.shouldExitForAlarm(now)) {
- conditionsToNotify.add(createCondition(
- conditionId, Condition.STATE_FALSE, "alarmCanceled"));
- addSnoozed(conditionId);
- } else {
- conditionsToNotify.add(createCondition(
- conditionId, Condition.STATE_TRUE, "meetsSchedule"));
- }
- cal.maybeSetNextAlarm(now, nextUserAlarmTime);
- } else {
- conditionsToNotify.add(createCondition(
- conditionId, Condition.STATE_FALSE, "!meetsSchedule"));
- removeSnoozed(conditionId);
- if (cal != null && nextUserAlarmTime == 0) {
- cal.maybeSetNextAlarm(now, nextUserAlarmTime);
- }
- }
- if (cal != null) {
- final long nextChangeTime = cal.getNextChangeTime(now);
- if (nextChangeTime > 0 && nextChangeTime > now) {
- if (mNextAlarmTime == 0 || nextChangeTime < mNextAlarmTime) {
- mNextAlarmTime = nextChangeTime;
- }
- }
+ Condition condition =
+ evaluateSubscriptionLocked(conditionId, mSubscriptions.get(conditionId),
+ now, nextUserAlarmTime);
+ if (condition != null) {
+ conditionsToNotify.add(condition);
}
}
}
@@ -202,6 +181,39 @@
updateAlarm(now, mNextAlarmTime);
}
+ @VisibleForTesting
+ @GuardedBy("mSubscriptions")
+ Condition evaluateSubscriptionLocked(Uri conditionId, ScheduleCalendar cal,
+ long now, long nextUserAlarmTime) {
+ Condition condition;
+ if (cal == null) {
+ condition = createCondition(conditionId, Condition.STATE_ERROR, "!invalidId");
+ removeSnoozed(conditionId);
+ return condition;
+ }
+ if (cal.isInSchedule(now)) {
+ if (conditionSnoozed(conditionId)) {
+ condition = createCondition(conditionId, Condition.STATE_FALSE, "snoozed");
+ } else if (cal.shouldExitForAlarm(now)) {
+ condition = createCondition(conditionId, Condition.STATE_FALSE, "alarmCanceled");
+ addSnoozed(conditionId);
+ } else {
+ condition = createCondition(conditionId, Condition.STATE_TRUE, "meetsSchedule");
+ }
+ } else {
+ condition = createCondition(conditionId, Condition.STATE_FALSE, "!meetsSchedule");
+ removeSnoozed(conditionId);
+ }
+ cal.maybeSetNextAlarm(now, nextUserAlarmTime);
+ final long nextChangeTime = cal.getNextChangeTime(now);
+ if (nextChangeTime > 0 && nextChangeTime > now) {
+ if (mNextAlarmTime == 0 || nextChangeTime < mNextAlarmTime) {
+ mNextAlarmTime = nextChangeTime;
+ }
+ }
+ return condition;
+ }
+
private void updateAlarm(long now, long time) {
final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext,
@@ -230,15 +242,6 @@
return cal != null && cal.isInSchedule(time);
}
- private static ScheduleCalendar toScheduleCalendar(Uri conditionId) {
- final ScheduleInfo schedule = ZenModeConfig.tryParseScheduleConditionId(conditionId);
- if (schedule == null || schedule.days == null || schedule.days.length == 0) return null;
- final ScheduleCalendar sc = new ScheduleCalendar();
- sc.setSchedule(schedule);
- sc.setTimeZone(TimeZone.getDefault());
- return sc;
- }
-
private void setRegistered(boolean registered) {
if (mRegistered == registered) return;
if (DEBUG) Slog.d(TAG, "setRegistered " + registered);
@@ -266,27 +269,28 @@
}
private boolean conditionSnoozed(Uri conditionId) {
- synchronized (mSnoozed) {
- return mSnoozed.contains(conditionId);
+ synchronized (mSnoozedForAlarm) {
+ return mSnoozedForAlarm.contains(conditionId);
}
}
- private void addSnoozed(Uri conditionId) {
- synchronized (mSnoozed) {
- mSnoozed.add(conditionId);
+ @VisibleForTesting
+ void addSnoozed(Uri conditionId) {
+ synchronized (mSnoozedForAlarm) {
+ mSnoozedForAlarm.add(conditionId);
saveSnoozedLocked();
}
}
private void removeSnoozed(Uri conditionId) {
- synchronized (mSnoozed) {
- mSnoozed.remove(conditionId);
+ synchronized (mSnoozedForAlarm) {
+ mSnoozedForAlarm.remove(conditionId);
saveSnoozedLocked();
}
}
- public void saveSnoozedLocked() {
- final String setting = TextUtils.join(SEPARATOR, mSnoozed);
+ private void saveSnoozedLocked() {
+ final String setting = TextUtils.join(SEPARATOR, mSnoozedForAlarm);
final int currentUser = ActivityManager.getCurrentUser();
Settings.Secure.putStringForUser(mContext.getContentResolver(),
SCP_SETTING,
@@ -294,8 +298,8 @@
currentUser);
}
- public void readSnoozed() {
- synchronized (mSnoozed) {
+ private void readSnoozed() {
+ synchronized (mSnoozedForAlarm) {
long identity = Binder.clearCallingIdentity();
try {
final String setting = Settings.Secure.getStringForUser(
@@ -312,7 +316,7 @@
if (TextUtils.isEmpty(token)) {
continue;
}
- mSnoozed.add(Uri.parse(token));
+ mSnoozedForAlarm.add(Uri.parse(token));
}
}
} finally {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 1e9fab5..700ccad 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -98,11 +98,6 @@
private final Metrics mMetrics = new Metrics();
private final ConditionProviders.Config mServiceConfig;
- protected final ArrayList<String> mDefaultRuleIds = new ArrayList<>();
- private final String EVENTS_DEFAULT_RULE = "EVENTS_DEFAULT_RULE";
- private final String SCHEDULED_DEFAULT_RULE_1 = "SCHEDULED_DEFAULT_RULE_1";
- private final String SCHEDULED_DEFAULT_RULE_2 = "SCHEDULED_DEFAULT_RULE_2";
-
@VisibleForTesting protected int mZenMode;
private int mUser = UserHandle.USER_SYSTEM;
@VisibleForTesting protected ZenModeConfig mConfig;
@@ -115,9 +110,8 @@
public static final long SUPPRESSED_EFFECT_ALL = SUPPRESSED_EFFECT_CALLS
| SUPPRESSED_EFFECT_NOTIFICATIONS;
- protected String mDefaultRuleWeeknightsName;
+ protected String mDefaultRuleEveryNightName;
protected String mDefaultRuleEventsName;
- protected String mDefaultRuleWeekendsName;
public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
mContext = context;
@@ -230,12 +224,25 @@
config = mDefaultConfig.copy();
config.user = user;
}
+ enforceDefaultRulesExist(config);
synchronized (mConfig) {
setConfigLocked(config, reason);
}
cleanUpZenRules();
}
+ private void enforceDefaultRulesExist(ZenModeConfig config) {
+ for (String id : ZenModeConfig.DEFAULT_RULE_IDS) {
+ if (!config.automaticRules.containsKey(id)) {
+ if (id.equals(ZenModeConfig.EVENTS_DEFAULT_RULE_ID)) {
+ appendDefaultEventRules(config);
+ } else if (id.equals(ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID)) {
+ appendDefaultEveryNightRule(config);
+ }
+ }
+ }
+ }
+
public int getZenModeListenerInterruptionFilter() {
return NotificationManager.zenModeToInterruptionFilter(mZenMode);
}
@@ -421,17 +428,12 @@
public void setDefaultZenRules(Context context) {
mDefaultConfig = readDefaultConfig(context.getResources());
-
- mDefaultRuleIds.add(EVENTS_DEFAULT_RULE);
- mDefaultRuleIds.add(SCHEDULED_DEFAULT_RULE_1);
- mDefaultRuleIds.add(SCHEDULED_DEFAULT_RULE_2);
-
appendDefaultRules(mDefaultConfig);
}
private void appendDefaultRules (ZenModeConfig config) {
getDefaultRuleNames();
- appendDefaultScheduleRules(config);
+ appendDefaultEveryNightRule(config);
appendDefaultEventRules(config);
}
@@ -450,7 +452,7 @@
protected void updateDefaultZenRules() {
ZenModeConfig configDefaultRules = new ZenModeConfig();
appendDefaultRules(configDefaultRules); // "new" localized default rules
- for (String ruleId : mDefaultRuleIds) {
+ for (String ruleId : ZenModeConfig.DEFAULT_RULE_IDS) {
AutomaticZenRule currRule = getAutomaticZenRule(ruleId);
ZenRule defaultRule = configDefaultRules.automaticRules.get(ruleId);
// if default rule wasn't customized, use localized name instead of previous
@@ -812,10 +814,8 @@
private void getDefaultRuleNames() {
// on locale-change, these values differ
- mDefaultRuleWeeknightsName = mContext.getResources()
- .getString(R.string.zen_mode_default_weeknights_name);
- mDefaultRuleWeekendsName = mContext.getResources()
- .getString(R.string.zen_mode_default_weekends_name);
+ mDefaultRuleEveryNightName = mContext.getResources()
+ .getString(R.string.zen_mode_default_every_night_name);
mDefaultRuleEventsName = mContext.getResources()
.getString(R.string.zen_mode_default_events_name);
}
@@ -935,39 +935,23 @@
return new ZenModeConfig();
}
- private void appendDefaultScheduleRules(ZenModeConfig config) {
+ private void appendDefaultEveryNightRule(ZenModeConfig config) {
if (config == null) return;
final ScheduleInfo weeknights = new ScheduleInfo();
- weeknights.days = ZenModeConfig.WEEKNIGHT_DAYS;
+ weeknights.days = ZenModeConfig.ALL_DAYS;
weeknights.startHour = 22;
weeknights.endHour = 7;
weeknights.exitAtAlarm = true;
- final ZenRule rule1 = new ZenRule();
- rule1.enabled = false;
- rule1.name = mDefaultRuleWeeknightsName;
- rule1.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
- rule1.zenMode = Global.ZEN_MODE_ALARMS;
- rule1.component = ScheduleConditionProvider.COMPONENT;
- rule1.id = SCHEDULED_DEFAULT_RULE_1;
- rule1.creationTime = System.currentTimeMillis();
- config.automaticRules.put(rule1.id, rule1);
-
- final ScheduleInfo weekends = new ScheduleInfo();
- weekends.days = ZenModeConfig.WEEKEND_DAYS;
- weekends.startHour = 23;
- weekends.startMinute = 30;
- weekends.endHour = 10;
- weekends.exitAtAlarm = true;
- final ZenRule rule2 = new ZenRule();
- rule2.enabled = false;
- rule2.name = mDefaultRuleWeekendsName;
- rule2.conditionId = ZenModeConfig.toScheduleConditionId(weekends);
- rule2.zenMode = Global.ZEN_MODE_ALARMS;
- rule2.component = ScheduleConditionProvider.COMPONENT;
- rule2.id = SCHEDULED_DEFAULT_RULE_2;
- rule2.creationTime = System.currentTimeMillis();
- config.automaticRules.put(rule2.id, rule2);
+ final ZenRule rule = new ZenRule();
+ rule.enabled = false;
+ rule.name = mDefaultRuleEveryNightName;
+ rule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
+ rule.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ rule.component = ScheduleConditionProvider.COMPONENT;
+ rule.id = ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID;
+ rule.creationTime = System.currentTimeMillis();
+ config.automaticRules.put(rule.id, rule);
}
private void appendDefaultEventRules(ZenModeConfig config) {
@@ -980,9 +964,9 @@
rule.enabled = false;
rule.name = mDefaultRuleEventsName;
rule.conditionId = ZenModeConfig.toEventConditionId(events);
- rule.zenMode = Global.ZEN_MODE_ALARMS;
+ rule.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
rule.component = EventConditionProvider.COMPONENT;
- rule.id = EVENTS_DEFAULT_RULE;
+ rule.id = ZenModeConfig.EVENTS_DEFAULT_RULE_ID;
rule.creationTime = System.currentTimeMillis();
config.automaticRules.put(rule.id, rule);
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 6a06be2..be66fe2 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -496,6 +496,26 @@
}
}
+ public boolean createProfileSnapshot(int appId, String packageName, String codePath)
+ throws InstallerException {
+ if (!checkBeforeRemote()) return false;
+ try {
+ return mInstalld.createProfileSnapshot(appId, packageName, codePath);
+ } catch (Exception e) {
+ throw InstallerException.from(e);
+ }
+ }
+
+ public void destroyProfileSnapshot(String packageName, String codePath)
+ throws InstallerException {
+ if (!checkBeforeRemote()) return;
+ try {
+ mInstalld.destroyProfileSnapshot(packageName, codePath);
+ } catch (Exception e) {
+ throw InstallerException.from(e);
+ }
+ }
+
public void invalidateMounts() throws InstallerException {
if (!checkBeforeRemote()) return;
try {
diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java
index 5f54c67..30072d4 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolver.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolver.java
@@ -40,14 +40,11 @@
import android.content.pm.InstantAppResolveInfo;
import android.content.pm.InstantAppResolveInfo.InstantAppDigest;
import android.metrics.LogMaker;
-import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
-import android.util.Pair;
-import android.util.Slog;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
@@ -56,11 +53,9 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
-import java.util.concurrent.TimeoutException;
/** @hide */
public abstract class InstantAppResolver {
@@ -159,8 +154,9 @@
long startTime) {
final String packageName;
final String splitName;
- final int versionCode;
+ final long versionCode;
final Intent failureIntent;
+ final Bundle extras;
if (instantAppResolveInfoList != null && instantAppResolveInfoList.size() > 0) {
final AuxiliaryResolveInfo instantAppIntentInfo =
InstantAppResolver.filterInstantAppIntent(
@@ -172,17 +168,20 @@
splitName = instantAppIntentInfo.splitName;
versionCode = instantAppIntentInfo.resolveInfo.getVersionCode();
failureIntent = instantAppIntentInfo.failureIntent;
+ extras = instantAppIntentInfo.resolveInfo.getExtras();
} else {
packageName = null;
splitName = null;
versionCode = -1;
failureIntent = null;
+ extras = null;
}
} else {
packageName = null;
splitName = null;
versionCode = -1;
failureIntent = null;
+ extras = null;
}
final Intent installerIntent = buildEphemeralInstallerIntent(
Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE,
@@ -197,6 +196,7 @@
requestObj.responseObj.installFailureActivity,
versionCode,
token,
+ extras,
false /*needsPhaseTwo*/);
installerIntent.setComponent(new ComponentName(
instantAppInstaller.packageName, instantAppInstaller.name));
@@ -241,8 +241,9 @@
@NonNull String instantAppPackageName,
@Nullable String instantAppSplitName,
@Nullable ComponentName installFailureActivity,
- int versionCode,
+ long versionCode,
@Nullable String token,
+ @Nullable Bundle extras,
boolean needsPhaseTwo) {
// Construct the intent that launches the instant installer
int flags = origIntent.getFlags();
@@ -258,6 +259,10 @@
if (origIntent.getData() != null) {
intent.putExtra(Intent.EXTRA_EPHEMERAL_HOSTNAME, origIntent.getData().getHost());
}
+ intent.putExtra(Intent.EXTRA_INSTANT_APP_ACTION, origIntent.getAction());
+ if (extras != null) {
+ intent.putExtra(Intent.EXTRA_INSTANT_APP_EXTRAS, extras);
+ }
// We have all of the data we need; just start the installer without a second phase
if (!needsPhaseTwo) {
@@ -307,7 +312,8 @@
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, instantAppPackageName);
intent.putExtra(Intent.EXTRA_SPLIT_NAME, instantAppSplitName);
- intent.putExtra(Intent.EXTRA_VERSION_CODE, versionCode);
+ intent.putExtra(Intent.EXTRA_VERSION_CODE, (int) (versionCode & 0x7fffffff));
+ intent.putExtra(Intent.EXTRA_LONG_VERSION_CODE, versionCode);
intent.putExtra(Intent.EXTRA_CALLING_PACKAGE, callingPackage);
if (verificationBundle != null) {
intent.putExtra(Intent.EXTRA_VERIFICATION_BUNDLE, verificationBundle);
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 00cfa31..730a9fd 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -128,6 +128,10 @@
int performDexOpt(PackageParser.Package pkg, String[] sharedLibraries,
String[] instructionSets, CompilerStats.PackageStats packageStats,
PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
+ if (pkg.applicationInfo.uid == -1) {
+ throw new IllegalArgumentException("Dexopt for " + pkg.packageName
+ + " has invalid uid.");
+ }
if (!canOptimizePackage(pkg)) {
return DEX_OPT_SKIPPED;
}
@@ -299,6 +303,9 @@
*/
public int dexOptSecondaryDexPath(ApplicationInfo info, String path,
PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) {
+ if (info.uid == -1) {
+ throw new IllegalArgumentException("Dexopt for path " + path + " has invalid uid.");
+ }
synchronized (mInstallLock) {
final long acquireTime = acquireWakeLockLI(info.uid);
try {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index be9b2f3..14128a7 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -27,7 +27,8 @@
import android.app.NotificationManager;
import android.app.PackageDeleteObserver;
import android.app.PackageInstallObserver;
-import android.app.admin.DevicePolicyManager;
+import android.app.admin.DeviceAdminInfo;
+import android.app.admin.DevicePolicyManagerInternal;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
@@ -704,20 +705,25 @@
mAppOps.checkPackage(callingUid, callerPackageName);
}
- // Check whether the caller is device owner, in which case we do it silently.
- DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
- Context.DEVICE_POLICY_SERVICE);
- boolean isDeviceOwner = (dpm != null) && dpm.isDeviceOwnerAppOnCallingUser(
- callerPackageName);
+ // Check whether the caller is device owner or affiliated profile owner, in which case we do
+ // it silently.
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ DevicePolicyManagerInternal dpmi =
+ LocalServices.getService(DevicePolicyManagerInternal.class);
+ final boolean isDeviceOwnerOrAffiliatedProfileOwner =
+ dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)
+ && dpmi.isUserAffiliatedWithDevice(callingUserId);
final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
- statusReceiver, versionedPackage.getPackageName(), isDeviceOwner, userId);
+ statusReceiver, versionedPackage.getPackageName(),
+ isDeviceOwnerOrAffiliatedProfileOwner, userId);
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
== PackageManager.PERMISSION_GRANTED) {
// Sweet, call straight through!
mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
- } else if (isDeviceOwner) {
- // Allow the DeviceOwner to silently delete packages
+ } else if (isDeviceOwnerOrAffiliatedProfileOwner) {
+ // Allow the device owner and affiliated profile owner to silently delete packages
// Need to clear the calling identity to get DELETE_PACKAGES permission
long ident = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 0e11cc7..5cf08dc 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -41,7 +41,8 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.admin.DevicePolicyManager;
+import android.app.admin.DeviceAdminInfo;
+import android.app.admin.DevicePolicyManagerInternal;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
@@ -91,6 +92,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
+import com.android.server.LocalServices;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
@@ -223,7 +225,7 @@
@GuardedBy("mLock")
private String mPackageName;
@GuardedBy("mLock")
- private int mVersionCode;
+ private long mVersionCode;
@GuardedBy("mLock")
private Signature[] mSignatures;
@GuardedBy("mLock")
@@ -311,14 +313,14 @@
};
/**
- * @return {@code true} iff the installing is app an device owner?
+ * @return {@code true} iff the installing is app an device owner or affiliated profile owner.
*/
- private boolean isInstallerDeviceOwnerLocked() {
- DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
- Context.DEVICE_POLICY_SERVICE);
-
- return (dpm != null) && dpm.isDeviceOwnerAppOnCallingUser(
- mInstallerPackageName);
+ private boolean isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked() {
+ DevicePolicyManagerInternal dpmi =
+ LocalServices.getService(DevicePolicyManagerInternal.class);
+ return dpmi != null && dpmi.isActiveAdminWithPolicy(mInstallerUid,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) && dpmi.isUserAffiliatedWithDevice(
+ userId);
}
/**
@@ -347,10 +349,10 @@
final boolean forcePermissionPrompt =
(params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
- // Device owners are allowed to silently install packages, so the permission check is
- // waived if the installer is the device owner.
+ // Device owners and affiliated profile owners are allowed to silently install packages, so
+ // the permission check is waived if the installer is the device owner.
return forcePermissionPrompt || !(isPermissionGranted || isInstallerRoot
- || isInstallerDeviceOwnerLocked());
+ || isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked());
}
public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
@@ -705,7 +707,8 @@
assertPreparedAndNotDestroyedLocked("commit");
final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(
- mContext, statusReceiver, sessionId, isInstallerDeviceOwnerLocked(), userId);
+ mContext, statusReceiver, sessionId,
+ isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId);
mRemoteObserver = adapter.getBinder();
if (forTransfer) {
@@ -1003,7 +1006,7 @@
// Use first package to define unknown values
if (mPackageName == null) {
mPackageName = apk.packageName;
- mVersionCode = apk.versionCode;
+ mVersionCode = apk.getLongVersionCode();
}
if (mSignatures == null) {
mSignatures = apk.signatures;
@@ -1054,7 +1057,7 @@
// ensure we've got appropriate package name, version code and signatures
if (mPackageName == null) {
mPackageName = pkgInfo.packageName;
- mVersionCode = pkgInfo.versionCode;
+ mVersionCode = pkgInfo.getLongVersionCode();
}
if (mSignatures == null) {
mSignatures = pkgInfo.signatures;
@@ -1146,7 +1149,7 @@
+ " specified package " + params.appPackageName
+ " inconsistent with " + apk.packageName);
}
- if (mVersionCode != apk.versionCode) {
+ if (mVersionCode != apk.getLongVersionCode()) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
+ " version code " + apk.versionCode + " inconsistent with "
+ mVersionCode);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9f7e3e8..e0f3ec7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -111,7 +111,6 @@
import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE;
import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS;
import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
-import static dalvik.system.DexFile.getNonProfileGuidedCompilerFilter;
import android.Manifest;
import android.annotation.IntDef;
@@ -187,6 +186,7 @@
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VerifierInfo;
import android.content.pm.VersionedPackage;
+import android.content.pm.dex.IArtManager;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
@@ -242,6 +242,8 @@
import android.util.ExceptionUtils;
import android.util.Log;
import android.util.LogPrinter;
+import android.util.LongSparseArray;
+import android.util.LongSparseLongArray;
import android.util.MathUtils;
import android.util.PackageUtils;
import android.util.Pair;
@@ -263,16 +265,13 @@
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.PackageHelper;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.IParcelFileDescriptorFactory;
-import com.android.internal.os.RoSystemProperties;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.Zygote;
import com.android.internal.telephony.CarrierAppUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
@@ -292,6 +291,7 @@
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.Settings.DatabaseVersion;
import com.android.server.pm.Settings.VersionInfo;
+import com.android.server.pm.dex.ArtManagerService;
import com.android.server.pm.dex.DexLogger;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
@@ -307,30 +307,23 @@
import com.android.server.storage.DeviceStorageMonitorInternal;
import dalvik.system.CloseGuard;
-import dalvik.system.DexFile;
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
-import libcore.io.Streams;
-import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
-import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -341,15 +334,12 @@
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
-import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
-import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -363,7 +353,6 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.zip.GZIPInputStream;
/**
* Keep track of all those APKs everywhere.
@@ -467,6 +456,7 @@
static final int SCAN_AS_SYSTEM = 1<<17;
static final int SCAN_AS_PRIVILEGED = 1<<18;
static final int SCAN_AS_OEM = 1<<19;
+ static final int SCAN_AS_VENDOR = 1<<20;
@IntDef(flag = true, prefix = { "SCAN_" }, value = {
SCAN_NO_DEX,
@@ -893,8 +883,8 @@
public final @Nullable String apk;
public final @NonNull SharedLibraryInfo info;
- SharedLibraryEntry(String _path, String _apk, String name, int version, int type,
- String declaringPackageName, int declaringPackageVersionCode) {
+ SharedLibraryEntry(String _path, String _apk, String name, long version, int type,
+ String declaringPackageName, long declaringPackageVersionCode) {
path = _path;
apk = _apk;
info = new SharedLibraryInfo(name, version, type, new VersionedPackage(
@@ -903,8 +893,8 @@
}
// Currently known shared libraries.
- final ArrayMap<String, SparseArray<SharedLibraryEntry>> mSharedLibraries = new ArrayMap<>();
- final ArrayMap<String, SparseArray<SharedLibraryEntry>> mStaticLibsByDeclaringPackage =
+ final ArrayMap<String, LongSparseArray<SharedLibraryEntry>> mSharedLibraries = new ArrayMap<>();
+ final ArrayMap<String, LongSparseArray<SharedLibraryEntry>> mStaticLibsByDeclaringPackage =
new ArrayMap<>();
// All available activities, for your resolving pleasure.
@@ -944,6 +934,8 @@
final PackageInstallerService mInstallerService;
+ final ArtManagerService mArtManagerService;
+
private final PackageDexOptimizer mPackageDexOptimizer;
// DexManager handles the usage of dex files (e.g. secondary files, whether or not a package
// is used by other apps).
@@ -2596,8 +2588,25 @@
| SCAN_AS_SYSTEM,
0);
- // Collect all vendor packages.
- File vendorAppDir = new File("/vendor/app");
+ // Collected privileged vendor packages.
+ File privilegedVendorAppDir = new File(Environment.getVendorDirectory(),
+ "priv-app");
+ try {
+ privilegedVendorAppDir = privilegedVendorAppDir.getCanonicalFile();
+ } catch (IOException e) {
+ // failed to look up canonical path, continue with original one
+ }
+ scanDirTracedLI(privilegedVendorAppDir,
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_VENDOR
+ | SCAN_AS_PRIVILEGED,
+ 0);
+
+ // Collect ordinary vendor packages.
+ File vendorAppDir = new File(Environment.getVendorDirectory(), "app");
try {
vendorAppDir = vendorAppDir.getCanonicalFile();
} catch (IOException e) {
@@ -2607,7 +2616,8 @@
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
- | SCAN_AS_SYSTEM,
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_VENDOR,
0);
// Collect all OEM packages.
@@ -2664,7 +2674,7 @@
+ ps.name + "; removing system app. Last known codePath="
+ ps.codePathString + ", installStatus=" + ps.installStatus
+ ", versionCode=" + ps.versionCode + "; scanned versionCode="
- + scannedPkg.mVersionCode);
+ + scannedPkg.getLongVersionCode());
removePackageLI(scannedPkg, true);
mExpectingBetter.put(ps.name, ps.codePath);
}
@@ -2792,13 +2802,23 @@
rescanFlags =
scanFlags
| SCAN_AS_SYSTEM;
+ } else if (FileUtils.contains(privilegedVendorAppDir, scanFile)) {
+ reparseFlags =
+ mDefParseFlags |
+ PackageParser.PARSE_IS_SYSTEM_DIR;
+ rescanFlags =
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_VENDOR
+ | SCAN_AS_PRIVILEGED;
} else if (FileUtils.contains(vendorAppDir, scanFile)) {
reparseFlags =
mDefParseFlags |
PackageParser.PARSE_IS_SYSTEM_DIR;
rescanFlags =
scanFlags
- | SCAN_AS_SYSTEM;
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_VENDOR;
} else if (FileUtils.contains(oemAppDir, scanFile)) {
reparseFlags =
mDefParseFlags |
@@ -3040,6 +3060,7 @@
}
mInstallerService = new PackageInstallerService(context, this);
+ mArtManagerService = new ArtManagerService(this, mInstaller, mInstallLock);
final Pair<ComponentName, String> instantAppResolverComponent =
getInstantAppResolverLPr();
if (instantAppResolverComponent != null) {
@@ -3852,7 +3873,7 @@
public PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage,
int flags, int userId) {
return getPackageInfoInternal(versionedPackage.getPackageName(),
- versionedPackage.getVersionCode(), flags, Binder.getCallingUid(), userId);
+ versionedPackage.getLongVersionCode(), flags, Binder.getCallingUid(), userId);
}
/**
@@ -3861,7 +3882,7 @@
* to clearing. Because it can only be provided by trusted code, it's value can be
* trusted and will be used as-is; unlike userId which will be validated by this method.
*/
- private PackageInfo getPackageInfoInternal(String packageName, int versionCode,
+ private PackageInfo getPackageInfoInternal(String packageName, long versionCode,
int flags, int filterCallingUid, int userId) {
if (!sUserManager.exists(userId)) return null;
flags = updateFlagsForPackage(flags, userId, packageName);
@@ -4058,7 +4079,7 @@
if (index < 0) {
continue;
}
- if (uidPs.pkg.usesStaticLibrariesVersions[index] == libEntry.info.getVersion()) {
+ if (uidPs.pkg.usesStaticLibrariesVersions[index] == libEntry.info.getLongVersion()) {
return false;
}
}
@@ -4454,7 +4475,8 @@
final int[] allUsers = sUserManager.getUserIds();
final int libCount = mSharedLibraries.size();
for (int i = 0; i < libCount; i++) {
- final SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i);
+ final LongSparseArray<SharedLibraryEntry> versionedLib
+ = mSharedLibraries.valueAt(i);
if (versionedLib == null) {
continue;
}
@@ -4471,7 +4493,8 @@
final VersionedPackage declaringPackage = libInfo.getDeclaringPackage();
// Resolve the package name - we use synthetic package names internally
final String internalPackageName = resolveInternalPackageNameLPr(
- declaringPackage.getPackageName(), declaringPackage.getVersionCode());
+ declaringPackage.getPackageName(),
+ declaringPackage.getLongVersionCode());
final PackageSetting ps = mSettings.getPackageLPr(internalPackageName);
// Skip unused static shared libs cached less than the min period
// to prevent pruning a lib needed by a subsequently installed package.
@@ -4482,7 +4505,7 @@
packagesToDelete = new ArrayList<>();
}
packagesToDelete.add(new VersionedPackage(internalPackageName,
- declaringPackage.getVersionCode()));
+ declaringPackage.getLongVersionCode()));
}
}
}
@@ -4492,7 +4515,7 @@
for (int i = 0; i < packageCount; i++) {
final VersionedPackage pkgToDelete = packagesToDelete.get(i);
// Delete the package synchronously (will fail of the lib used for any user).
- if (deletePackageX(pkgToDelete.getPackageName(), pkgToDelete.getVersionCode(),
+ if (deletePackageX(pkgToDelete.getPackageName(), pkgToDelete.getLongVersionCode(),
UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS)
== PackageManager.DELETE_SUCCEEDED) {
if (volume.getUsableSpace() >= neededSpace) {
@@ -4797,7 +4820,7 @@
final int libCount = mSharedLibraries.size();
for (int i = 0; i < libCount; i++) {
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i);
+ LongSparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i);
if (versionedLib == null) {
continue;
}
@@ -4821,7 +4844,7 @@
}
SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getName(),
- libInfo.getVersion(), libInfo.getType(),
+ libInfo.getLongVersion(), libInfo.getType(),
libInfo.getDeclaringPackage(), getPackagesUsingSharedLibraryLPr(libInfo,
flags, userId));
@@ -4857,7 +4880,7 @@
if (libIdx < 0) {
continue;
}
- if (ps.usesStaticLibrariesVersions[libIdx] != libInfo.getVersion()) {
+ if (ps.usesStaticLibrariesVersions[libIdx] != libInfo.getLongVersion()) {
continue;
}
if (versionedPackages == null) {
@@ -4938,7 +4961,7 @@
Set<String> libs = null;
final int libCount = mSharedLibraries.size();
for (int i = 0; i < libCount; i++) {
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i);
+ LongSparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i);
if (versionedLib == null) {
continue;
}
@@ -8067,24 +8090,24 @@
return finalList;
}
- private void scanDirTracedLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + dir.getAbsolutePath() + "]");
+ private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags, long currentTime) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
- scanDirLI(dir, parseFlags, scanFlags, currentTime);
+ scanDirLI(scanDir, parseFlags, scanFlags, currentTime);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
- private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
- final File[] files = dir.listFiles();
+ private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
+ final File[] files = scanDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
- Log.d(TAG, "No files in app dir " + dir);
+ Log.d(TAG, "No files in app dir " + scanDir);
return;
}
if (DEBUG_PACKAGE_SCANNING) {
- Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
+ Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags
+ " flags=0x" + Integer.toHexString(parseFlags));
}
try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
@@ -8116,7 +8139,7 @@
}
try {
if (errorCode == PackageManager.INSTALL_SUCCEEDED) {
- scanPackageLI(parseResult.pkg, parseResult.scanFile, parseFlags, scanFlags,
+ scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
currentTime, null);
}
} catch (PackageManagerException e) {
@@ -8148,14 +8171,14 @@
logCriticalInfo(priority, msg);
}
- private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg, File srcFile,
+ private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg,
final @ParseFlags int parseFlags) throws PackageManagerException {
// When upgrading from pre-N MR1, verify the package time stamp using the package
// directory and not the APK file.
final long lastModifiedTime = mIsPreNMR1Upgrade
- ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg, srcFile);
+ ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg);
if (ps != null
- && ps.codePath.equals(srcFile)
+ && ps.codePathString.equals(pkg.codePath)
&& ps.timeStamp == lastModifiedTime
&& !isCompatSignatureUpdateNeeded(pkg)
&& !isRecoverSignatureUpdateNeeded(pkg)) {
@@ -8178,7 +8201,7 @@
Slog.w(TAG, "PackageSetting for " + ps.name
+ " is missing signatures. Collecting certs again to recover them.");
} else {
- Slog.i(TAG, srcFile.toString() + " changed; collecting certs");
+ Slog.i(TAG, toString() + " changed; collecting certs");
}
try {
@@ -8233,14 +8256,14 @@
renameStaticSharedLibraryPackage(pkg);
}
- return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);
+ return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
}
/**
* Scans a package and returns the newly parsed package.
* @throws PackageManagerException on a parse error.
*/
- private PackageParser.Package scanPackageLI(PackageParser.Package pkg, File scanFile,
+ private PackageParser.Package scanPackageChildLI(PackageParser.Package pkg,
final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user)
throws PackageManagerException {
@@ -8258,20 +8281,20 @@
}
// Scan the parent
- PackageParser.Package scannedPkg = scanPackageInternalLI(pkg, scanFile, parseFlags,
+ PackageParser.Package scannedPkg = scanPackageInternalLI(pkg, parseFlags,
scanFlags, currentTime, user);
// Scan the children
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPackage = pkg.childPackages.get(i);
- scanPackageInternalLI(childPackage, scanFile, parseFlags, scanFlags,
+ scanPackageInternalLI(childPackage, parseFlags, scanFlags,
currentTime, user);
}
if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
- return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);
+ return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
}
return scannedPkg;
@@ -8281,12 +8304,12 @@
* Scans a package and returns the newly parsed package.
* @throws PackageManagerException on a parse error.
*/
- private PackageParser.Package scanPackageInternalLI(PackageParser.Package pkg, File scanFile,
+ private PackageParser.Package scanPackageInternalLI(PackageParser.Package pkg,
@ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user)
throws PackageManagerException {
PackageSetting ps = null;
- PackageSetting updatedPkg;
+ PackageSetting updatedPs;
// reader
synchronized (mPackages) {
// Look to see if we already know about this package.
@@ -8303,8 +8326,8 @@
// Check to see if this package could be hiding/updating a system
// package. Must look for it either under the original or real
// package name depending on our state.
- updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
- if (DEBUG_INSTALL && updatedPkg != null) Slog.d(TAG, "updatedPkg = " + updatedPkg);
+ updatedPs = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
+ if (DEBUG_INSTALL && updatedPs != null) Slog.d(TAG, "updatedPkg = " + updatedPs);
// If this is a package we don't know about on the system partition, we
// may need to remove disabled child packages on the system partition
@@ -8338,59 +8361,67 @@
}
}
- final boolean isUpdatedPkg = updatedPkg != null;
+ final boolean isUpdatedPkg = updatedPs != null;
final boolean isUpdatedSystemPkg = isUpdatedPkg && (scanFlags & SCAN_AS_SYSTEM) != 0;
boolean isUpdatedPkgBetter = false;
// First check if this is a system package that may involve an update
if (isUpdatedSystemPkg) {
// If new package is not located in "/system/priv-app" (e.g. due to an OTA),
// it needs to drop FLAG_PRIVILEGED.
- if (locationIsPrivileged(scanFile)) {
- updatedPkg.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+ if (locationIsPrivileged(pkg.codePath)) {
+ updatedPs.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
} else {
- updatedPkg.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+ updatedPs.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
// If new package is not located in "/oem" (e.g. due to an OTA),
// it needs to drop FLAG_OEM.
- if (locationIsOem(scanFile)) {
- updatedPkg.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_OEM;
+ if (locationIsOem(pkg.codePath)) {
+ updatedPs.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_OEM;
} else {
- updatedPkg.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_OEM;
+ updatedPs.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_OEM;
+ }
+ // If new package is not located in "/vendor" (e.g. due to an OTA),
+ // it needs to drop FLAG_VENDOR.
+ if (locationIsVendor(pkg.codePath)) {
+ updatedPs.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR;
+ } else {
+ updatedPs.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_VENDOR;
}
- if (ps != null && !ps.codePath.equals(scanFile)) {
+ if (ps != null && !ps.codePathString.equals(pkg.codePath)) {
// The path has changed from what was last scanned... check the
// version of the new path against what we have stored to determine
// what to do.
if (DEBUG_INSTALL) Slog.d(TAG, "Path changing from " + ps.codePath);
- if (pkg.mVersionCode <= ps.versionCode) {
+ if (pkg.getLongVersionCode() <= ps.versionCode) {
// The system package has been updated and the code path does not match
// Ignore entry. Skip it.
- if (DEBUG_INSTALL) Slog.i(TAG, "Package " + ps.name + " at " + scanFile
+ if (DEBUG_INSTALL) Slog.i(TAG, "Package " + ps.name + " at " + pkg.codePath
+ " ignored: updated version " + ps.versionCode
- + " better than this " + pkg.mVersionCode);
- if (!updatedPkg.codePath.equals(scanFile)) {
+ + " better than this " + pkg.getLongVersionCode());
+ if (!updatedPs.codePathString.equals(pkg.codePath)) {
Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg "
- + ps.name + " changing from " + updatedPkg.codePathString
- + " to " + scanFile);
- updatedPkg.codePath = scanFile;
- updatedPkg.codePathString = scanFile.toString();
- updatedPkg.resourcePath = scanFile;
- updatedPkg.resourcePathString = scanFile.toString();
+ + ps.name + " changing from " + updatedPs.codePathString
+ + " to " + pkg.codePath);
+ final File codePath = new File(pkg.codePath);
+ updatedPs.codePath = codePath;
+ updatedPs.codePathString = pkg.codePath;
+ updatedPs.resourcePath = codePath;
+ updatedPs.resourcePathString = pkg.codePath;
}
- updatedPkg.pkg = pkg;
- updatedPkg.versionCode = pkg.mVersionCode;
+ updatedPs.pkg = pkg;
+ updatedPs.versionCode = pkg.getLongVersionCode();
// Update the disabled system child packages to point to the package too.
- final int childCount = updatedPkg.childPackageNames != null
- ? updatedPkg.childPackageNames.size() : 0;
+ final int childCount = updatedPs.childPackageNames != null
+ ? updatedPs.childPackageNames.size() : 0;
for (int i = 0; i < childCount; i++) {
- String childPackageName = updatedPkg.childPackageNames.get(i);
+ String childPackageName = updatedPs.childPackageNames.get(i);
PackageSetting updatedChildPkg = mSettings.getDisabledSystemPkgLPr(
childPackageName);
if (updatedChildPkg != null) {
updatedChildPkg.pkg = pkg;
- updatedChildPkg.versionCode = pkg.mVersionCode;
+ updatedChildPkg.versionCode = pkg.getLongVersionCode();
}
}
} else {
@@ -8406,9 +8437,9 @@
mPackages.remove(ps.name);
}
- logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile
+ logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + pkg.codePath
+ " reverting from " + ps.codePathString
- + ": new version " + pkg.mVersionCode
+ + ": new version " + pkg.getLongVersionCode()
+ " better than installed " + ps.versionCode);
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
@@ -8453,17 +8484,17 @@
if (isUpdatedSystemPkg && !isUpdatedPkgBetter) {
// Set CPU Abis to application info.
if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) {
- final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, updatedPkg);
- derivePackageAbi(pkg, scanFile, cpuAbiOverride, false, mAppLib32InstallDir);
+ final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, updatedPs);
+ derivePackageAbi(pkg, cpuAbiOverride, false, mAppLib32InstallDir);
} else {
- pkg.applicationInfo.primaryCpuAbi = updatedPkg.primaryCpuAbiString;
- pkg.applicationInfo.secondaryCpuAbi = updatedPkg.secondaryCpuAbiString;
+ pkg.applicationInfo.primaryCpuAbi = updatedPs.primaryCpuAbiString;
+ pkg.applicationInfo.secondaryCpuAbi = updatedPs.secondaryCpuAbiString;
}
- pkg.mExtras = updatedPkg;
+ pkg.mExtras = updatedPs;
- throw new PackageManagerException(Log.WARN, "Package " + ps.name + " at "
- + scanFile + " ignored: updated version " + ps.versionCode
- + " better than this " + pkg.mVersionCode);
+ throw new PackageManagerException(Log.WARN, "Package " + pkg.packageName + " at "
+ + pkg.codePath + " ignored: updated version " + updatedPs.versionCode
+ + " better than this " + pkg.getLongVersionCode());
}
if (isUpdatedPkg) {
@@ -8472,19 +8503,25 @@
// An updated privileged application will not have the PARSE_IS_PRIVILEGED
// flag set initially
- if ((updatedPkg.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
+ if ((updatedPs.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
scanFlags |= SCAN_AS_PRIVILEGED;
}
- // An updated OEM app will not have the PARSE_IS_OEM
+ // An updated OEM app will not have the SCAN_AS_OEM
// flag set initially
- if ((updatedPkg.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0) {
+ if ((updatedPs.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0) {
scanFlags |= SCAN_AS_OEM;
}
+
+ // An updated vendor app will not have the SCAN_AS_VENDOR
+ // flag set initially
+ if ((updatedPs.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0) {
+ scanFlags |= SCAN_AS_VENDOR;
+ }
}
// Verify certificates against what was last scanned
- collectCertificatesLI(ps, pkg, scanFile, parseFlags);
+ collectCertificatesLI(ps, pkg, parseFlags);
/*
* A new system app appeared, but we already had a non-system one of the
@@ -8512,11 +8549,11 @@
* already installed version, hide it. It will be scanned later
* and re-added like an update.
*/
- if (pkg.mVersionCode <= ps.versionCode) {
+ if (pkg.getLongVersionCode() <= ps.versionCode) {
shouldHideSystemApp = true;
- logCriticalInfo(Log.INFO, "Package " + ps.name + " appeared at " + scanFile
- + " but new version " + pkg.mVersionCode + " better than installed "
- + ps.versionCode + "; hiding system");
+ logCriticalInfo(Log.INFO, "Package " + ps.name + " appeared at " + pkg.codePath
+ + " but new version " + pkg.getLongVersionCode()
+ + " better than installed " + ps.versionCode + "; hiding system");
} else {
/*
* The newly found system app is a newer version that the
@@ -8524,9 +8561,10 @@
* already-installed application and replace it with our own
* while keeping the application data.
*/
- logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile
+ logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + pkg.codePath
+ " reverting from " + ps.codePathString + ": new version "
- + pkg.mVersionCode + " better than installed " + ps.versionCode);
+ + pkg.getLongVersionCode() + " better than installed "
+ + ps.versionCode);
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
synchronized (mInstallLock) {
@@ -9104,12 +9142,12 @@
}
}
- private void findSharedNonSystemLibrariesRecursive(ArrayList<String> libs, int[] versions,
+ private void findSharedNonSystemLibrariesRecursive(ArrayList<String> libs, long[] versions,
ArrayList<PackageParser.Package> collected, Set<String> collectedNames) {
final int libNameCount = libs.size();
for (int i = 0; i < libNameCount; i++) {
String libName = libs.get(i);
- int version = (versions != null && versions.length == libNameCount)
+ long version = (versions != null && versions.length == libNameCount)
? versions[i] : PackageManager.VERSION_CODE_HIGHEST;
PackageParser.Package libPkg = findSharedNonSystemLibrary(libName, version);
if (libPkg != null) {
@@ -9118,7 +9156,7 @@
}
}
- private PackageParser.Package findSharedNonSystemLibrary(String name, int version) {
+ private PackageParser.Package findSharedNonSystemLibrary(String name, long version) {
synchronized (mPackages) {
SharedLibraryEntry libEntry = getSharedLibraryEntryLPr(name, version);
if (libEntry != null) {
@@ -9128,8 +9166,8 @@
}
}
- private SharedLibraryEntry getSharedLibraryEntryLPr(String name, int version) {
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name);
+ private SharedLibraryEntry getSharedLibraryEntryLPr(String name, long version) {
+ LongSparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name);
if (versionedLib == null) {
return null;
}
@@ -9137,15 +9175,15 @@
}
private SharedLibraryEntry getLatestSharedLibraVersionLPr(PackageParser.Package pkg) {
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(
+ LongSparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(
pkg.staticSharedLibName);
if (versionedLib == null) {
return null;
}
- int previousLibVersion = -1;
+ long previousLibVersion = -1;
final int versionCount = versionedLib.size();
for (int i = 0; i < versionCount; i++) {
- final int libVersion = versionedLib.keyAt(i);
+ final long libVersion = versionedLib.keyAt(i);
if (libVersion < pkg.staticSharedLibVersion) {
previousLibVersion = Math.max(previousLibVersion, libVersion);
}
@@ -9429,14 +9467,14 @@
}
private Set<String> addSharedLibrariesLPw(@NonNull List<String> requestedLibraries,
- @Nullable int[] requiredVersions, @Nullable String[][] requiredCertDigests,
+ @Nullable long[] requiredVersions, @Nullable String[][] requiredCertDigests,
@NonNull String packageName, @Nullable PackageParser.Package changingLib,
boolean required, int targetSdk, @Nullable Set<String> outUsedLibraries)
throws PackageManagerException {
final int libCount = requestedLibraries.size();
for (int i = 0; i < libCount; i++) {
final String libName = requestedLibraries.get(i);
- final int libVersion = requiredVersions != null ? requiredVersions[i]
+ final long libVersion = requiredVersions != null ? requiredVersions[i]
: SharedLibraryInfo.VERSION_UNDEFINED;
final SharedLibraryEntry libEntry = getSharedLibraryEntryLPr(libName, libVersion);
if (libEntry == null) {
@@ -9451,11 +9489,11 @@
}
} else {
if (requiredVersions != null && requiredCertDigests != null) {
- if (libEntry.info.getVersion() != requiredVersions[i]) {
+ if (libEntry.info.getLongVersion() != requiredVersions[i]) {
throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
"Package " + packageName + " requires unavailable static shared"
+ " library " + libName + " version "
- + libEntry.info.getVersion() + "; failing!");
+ + libEntry.info.getLongVersion() + "; failing!");
}
PackageParser.Package libPkg = mPackages.get(libEntry.apk);
@@ -9479,7 +9517,7 @@
if (expectedCertDigests.length != libCertDigests.length) {
throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
"Package " + packageName + " requires differently signed" +
- " static sDexLoadReporter.java:45.19hared library; failing!");
+ " static shared library; failing!");
}
// Use a predictable order as signature order may vary
@@ -9698,6 +9736,7 @@
// them in the case where we're not upgrading or booting for the first time.
String primaryCpuAbiFromSettings = null;
String secondaryCpuAbiFromSettings = null;
+ boolean needToDeriveAbi = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0;
// writer
synchronized (mPackages) {
@@ -9775,11 +9814,14 @@
}
}
- if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) == 0) {
+ if (!needToDeriveAbi) {
PackageSetting foundPs = mSettings.getPackageLPr(pkg.packageName);
if (foundPs != null) {
primaryCpuAbiFromSettings = foundPs.primaryCpuAbiString;
secondaryCpuAbiFromSettings = foundPs.secondaryCpuAbiString;
+ } else {
+ // when re-adding a system package failed after uninstalling updates.
+ needToDeriveAbi = true;
}
}
@@ -9814,7 +9856,7 @@
pkgSetting = Settings.createNewSetting(pkg.packageName, origPackage,
disabledPkgSetting, realName, suid, destCodeFile, destResourceFile,
pkg.applicationInfo.nativeLibraryRootDir, pkg.applicationInfo.primaryCpuAbi,
- pkg.applicationInfo.secondaryCpuAbi, pkg.mVersionCode,
+ pkg.applicationInfo.secondaryCpuAbi, pkg.getLongVersionCode(),
pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags, user,
true /*allowInstall*/, instantApp, virtualPreload,
parentPackageName, pkg.getChildPackageNames(),
@@ -9995,11 +10037,10 @@
final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
- if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) {
+ if (needToDeriveAbi) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
final boolean extractNativeLibs = !pkg.isLibrary();
- derivePackageAbi(pkg, scanFile, cpuAbiOverride, extractNativeLibs,
- mAppLib32InstallDir);
+ derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs, mAppLib32InstallDir);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
// Some system apps still use directory structure for native libraries
@@ -10106,7 +10147,7 @@
}
// Take care of first install / last update times.
- final long scanFileTime = getLastModifiedTime(pkg, scanFile);
+ final long scanFileTime = getLastModifiedTime(pkg);
if (currentTime != 0) {
if (pkgSetting.firstInstallTime == 0) {
pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime;
@@ -10230,6 +10271,10 @@
pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_OEM;
}
+ if ((scanFlags & SCAN_AS_VENDOR) != 0) {
+ pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR;
+ }
+
if (!isSystemApp(pkg)) {
// Only system apps can use these features.
pkg.mOriginalPackages = null;
@@ -10379,20 +10424,20 @@
}
// The version codes must be ordered as lib versions
- int minVersionCode = Integer.MIN_VALUE;
- int maxVersionCode = Integer.MAX_VALUE;
+ long minVersionCode = Long.MIN_VALUE;
+ long maxVersionCode = Long.MAX_VALUE;
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(
+ LongSparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(
pkg.staticSharedLibName);
if (versionedLib != null) {
final int versionCount = versionedLib.size();
for (int i = 0; i < versionCount; i++) {
SharedLibraryInfo libInfo = versionedLib.valueAt(i).info;
- final int libVersionCode = libInfo.getDeclaringPackage()
- .getVersionCode();
- if (libInfo.getVersion() < pkg.staticSharedLibVersion) {
+ final long libVersionCode = libInfo.getDeclaringPackage()
+ .getLongVersionCode();
+ if (libInfo.getLongVersion() < pkg.staticSharedLibVersion) {
minVersionCode = Math.max(minVersionCode, libVersionCode + 1);
- } else if (libInfo.getVersion() > pkg.staticSharedLibVersion) {
+ } else if (libInfo.getLongVersion() > pkg.staticSharedLibVersion) {
maxVersionCode = Math.min(maxVersionCode, libVersionCode - 1);
} else {
minVersionCode = maxVersionCode = libVersionCode;
@@ -10400,7 +10445,8 @@
}
}
}
- if (pkg.mVersionCode < minVersionCode || pkg.mVersionCode > maxVersionCode) {
+ if (pkg.getLongVersionCode() < minVersionCode
+ || pkg.getLongVersionCode() > maxVersionCode) {
throw new PackageManagerException("Static shared"
+ " lib version codes must be ordered as lib versions");
}
@@ -10490,11 +10536,11 @@
}
}
- private boolean addSharedLibraryLPw(String path, String apk, String name, int version,
- int type, String declaringPackageName, int declaringVersionCode) {
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name);
+ private boolean addSharedLibraryLPw(String path, String apk, String name, long version,
+ int type, String declaringPackageName, long declaringVersionCode) {
+ LongSparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name);
if (versionedLib == null) {
- versionedLib = new SparseArray<>();
+ versionedLib = new LongSparseArray<>();
mSharedLibraries.put(name, versionedLib);
if (type == SharedLibraryInfo.TYPE_STATIC) {
mStaticLibsByDeclaringPackage.put(declaringPackageName, versionedLib);
@@ -10508,8 +10554,8 @@
return true;
}
- private boolean removeSharedLibraryLPw(String name, int version) {
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name);
+ private boolean removeSharedLibraryLPw(String name, long version) {
+ LongSparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name);
if (versionedLib == null) {
return false;
}
@@ -10548,6 +10594,7 @@
// Set up information for our fall-back user intent resolution activity.
mPlatformPackage = pkg;
pkg.mVersionCode = mSdkVersion;
+ pkg.mVersionCodeMajor = 0;
mAndroidApplication = pkg.applicationInfo;
if (!mResolverReplaced) {
mResolveActivity.applicationInfo = mAndroidApplication;
@@ -10589,7 +10636,7 @@
// names to allow install of multiple versions, so use name from manifest.
if (addSharedLibraryLPw(null, pkg.packageName, pkg.staticSharedLibName,
pkg.staticSharedLibVersion, SharedLibraryInfo.TYPE_STATIC,
- pkg.manifestPackageName, pkg.mVersionCode)) {
+ pkg.manifestPackageName, pkg.getLongVersionCode())) {
hasStaticSharedLibs = true;
} else {
Slog.w(TAG, "Package " + pkg.packageName + " library "
@@ -10635,7 +10682,7 @@
if (!addSharedLibraryLPw(null, pkg.packageName, name,
SharedLibraryInfo.VERSION_UNDEFINED,
SharedLibraryInfo.TYPE_DYNAMIC,
- pkg.packageName, pkg.mVersionCode)) {
+ pkg.packageName, pkg.getLongVersionCode())) {
Slog.w(TAG, "Package " + pkg.packageName + " library "
+ name + " already exists; skipping");
}
@@ -10886,10 +10933,9 @@
*
* If {@code extractLibs} is true, native libraries are extracted from the app if required.
*/
- private static void derivePackageAbi(PackageParser.Package pkg, File scanFile,
- String cpuAbiOverride, boolean extractLibs,
- File appLib32InstallDir)
- throws PackageManagerException {
+ private static void derivePackageAbi(PackageParser.Package pkg, String cpuAbiOverride,
+ boolean extractLibs, File appLib32InstallDir)
+ throws PackageManagerException {
// Give ourselves some initial paths; we'll come back for another
// pass once we've determined ABI below.
setNativeLibraryPaths(pkg, appLib32InstallDir);
@@ -14664,6 +14710,9 @@
verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,
pkgLite.versionCode);
+ verification.putExtra(PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE,
+ pkgLite.getLongVersionCode());
+
if (verificationInfo != null) {
if (verificationInfo.originatingUri != null) {
verification.putExtra(Intent.EXTRA_ORIGINATING_URI,
@@ -15055,7 +15104,12 @@
resourceFile = afterCodeFile;
// Reflect the rename in scanned details
- pkg.setCodePath(afterCodeFile.getAbsolutePath());
+ try {
+ pkg.setCodePath(afterCodeFile.getCanonicalPath());
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to get path: " + afterCodeFile, e);
+ return false;
+ }
pkg.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,
afterCodeFile, pkg.baseCodePath));
pkg.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
@@ -15544,6 +15598,15 @@
return;
}
+ // check if the new package supports all of the abis which the old package supports
+ boolean oldPkgSupportMultiArch = oldPackage.applicationInfo.secondaryCpuAbi != null;
+ boolean newPkgSupportMultiArch = pkg.applicationInfo.secondaryCpuAbi != null;
+ if (isSystemApp(oldPackage) && oldPkgSupportMultiArch && !newPkgSupportMultiArch) {
+ res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+ "Update to package " + pkgName + " doesn't support multi arch");
+ return;
+ }
+
// In case of rollback, remember per-user/profile install state
allUsers = sUserManager.getUserIds();
installedUsers = ps.queryInstalledUsers(allUsers, true);
@@ -15625,18 +15688,22 @@
boolean sysPkg = (isSystemApp(oldPackage));
if (sysPkg) {
- // Set the system/privileged/oem flags as needed
+ // Set the system/privileged/oem/vendor flags as needed
final boolean privileged =
(oldPackage.applicationInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
final boolean oem =
(oldPackage.applicationInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
+ final boolean vendor =
+ (oldPackage.applicationInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
final @ParseFlags int systemParseFlags = parseFlags;
final @ScanFlags int systemScanFlags = scanFlags
| SCAN_AS_SYSTEM
| (privileged ? SCAN_AS_PRIVILEGED : 0)
- | (oem ? SCAN_AS_OEM : 0);
+ | (oem ? SCAN_AS_OEM : 0)
+ | (vendor ? SCAN_AS_VENDOR : 0);
replaceSystemPackageLIF(oldPackage, pkg, systemParseFlags, systemScanFlags,
user, allUsers, installerPackageName, res, installReason);
@@ -16537,8 +16604,7 @@
String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
args.abiOverride : pkg.cpuAbiOverride);
final boolean extractNativeLibs = !pkg.isLibrary();
- derivePackageAbi(pkg, new File(pkg.codePath), abiOverride,
- extractNativeLibs, mAppLib32InstallDir);
+ derivePackageAbi(pkg, abiOverride, extractNativeLibs, mAppLib32InstallDir);
} catch (PackageManagerException pme) {
Slog.e(TAG, "Error deriving application ABI", pme);
res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
@@ -16560,50 +16626,6 @@
return;
}
- // Verify if we need to dexopt the app.
- //
- // NOTE: it is *important* to call dexopt after doRename which will sync the
- // package data from PackageParser.Package and its corresponding ApplicationInfo.
- //
- // We only need to dexopt if the package meets ALL of the following conditions:
- // 1) it is not forward locked.
- // 2) it is not on on an external ASEC container.
- // 3) it is not an instant app or if it is then dexopt is enabled via gservices.
- //
- // Note that we do not dexopt instant apps by default. dexopt can take some time to
- // complete, so we skip this step during installation. Instead, we'll take extra time
- // the first time the instant app starts. It's preferred to do it this way to provide
- // continuous progress to the useur instead of mysteriously blocking somewhere in the
- // middle of running an instant app. The default behaviour can be overridden
- // via gservices.
- final boolean performDexopt = !forwardLocked
- && !pkg.applicationInfo.isExternalAsec()
- && (!instantApp || Global.getInt(mContext.getContentResolver(),
- Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0);
-
- if (performDexopt) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
- // Do not run PackageDexOptimizer through the local performDexOpt
- // method because `pkg` may not be in `mPackages` yet.
- //
- // Also, don't fail application installs if the dexopt step fails.
- DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,
- REASON_INSTALL,
- DexoptOptions.DEXOPT_BOOT_COMPLETE);
- mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
- null /* instructionSets */,
- getOrCreateCompilerPackageStats(pkg),
- mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
- dexoptOptions);
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
-
- // Notify BackgroundDexOptService that the package has been changed.
- // If this is an update of a package which used to fail to compile,
- // BackgroundDexOptService will remove it from its blacklist.
- // TODO: Layering violation
- BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
-
if (!instantApp) {
startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
} else {
@@ -16621,7 +16643,8 @@
// unless this is the exact same version code which is useful for
// development.
PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
- if (existingPkg != null && existingPkg.mVersionCode != pkg.mVersionCode) {
+ if (existingPkg != null &&
+ existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) {
res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring "
+ "static-shared libs cannot be updated");
return;
@@ -16635,6 +16658,55 @@
}
}
+ // Check whether we need to dexopt the app.
+ //
+ // NOTE: it is IMPORTANT to call dexopt:
+ // - after doRename which will sync the package data from PackageParser.Package and its
+ // corresponding ApplicationInfo.
+ // - after installNewPackageLIF or replacePackageLIF which will update result with the
+ // uid of the application (pkg.applicationInfo.uid).
+ // This update happens in place!
+ //
+ // We only need to dexopt if the package meets ALL of the following conditions:
+ // 1) it is not forward locked.
+ // 2) it is not on on an external ASEC container.
+ // 3) it is not an instant app or if it is then dexopt is enabled via gservices.
+ //
+ // Note that we do not dexopt instant apps by default. dexopt can take some time to
+ // complete, so we skip this step during installation. Instead, we'll take extra time
+ // the first time the instant app starts. It's preferred to do it this way to provide
+ // continuous progress to the useur instead of mysteriously blocking somewhere in the
+ // middle of running an instant app. The default behaviour can be overridden
+ // via gservices.
+ final boolean performDexopt = (res.returnCode == PackageManager.INSTALL_SUCCEEDED)
+ && !forwardLocked
+ && !pkg.applicationInfo.isExternalAsec()
+ && (!instantApp || Global.getInt(mContext.getContentResolver(),
+ Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0);
+
+ if (performDexopt) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+ // Do not run PackageDexOptimizer through the local performDexOpt
+ // method because `pkg` may not be in `mPackages` yet.
+ //
+ // Also, don't fail application installs if the dexopt step fails.
+ DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,
+ REASON_INSTALL,
+ DexoptOptions.DEXOPT_BOOT_COMPLETE);
+ mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
+ null /* instructionSets */,
+ getOrCreateCompilerPackageStats(pkg),
+ mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
+ dexoptOptions);
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ // Notify BackgroundDexOptService that the package has been changed.
+ // If this is an update of a package which used to fail to compile,
+ // BackgroundDexOptService will remove it from its blacklist.
+ // TODO: Layering violation
+ BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
+
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
@@ -16811,6 +16883,10 @@
return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
}
+ private static boolean isVendorApp(PackageParser.Package pkg) {
+ return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
+ }
+
private static boolean hasDomainURLs(PackageParser.Package pkg) {
return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0;
}
@@ -16875,17 +16951,16 @@
final boolean canViewInstantApps = canViewInstantApps(callingUid, userId);
Preconditions.checkNotNull(versionedPackage);
Preconditions.checkNotNull(observer);
- Preconditions.checkArgumentInRange(versionedPackage.getVersionCode(),
+ Preconditions.checkArgumentInRange(versionedPackage.getLongVersionCode(),
PackageManager.VERSION_CODE_HIGHEST,
- Integer.MAX_VALUE, "versionCode must be >= -1");
+ Long.MAX_VALUE, "versionCode must be >= -1");
final String packageName = versionedPackage.getPackageName();
- final int versionCode = versionedPackage.getVersionCode();
+ final long versionCode = versionedPackage.getLongVersionCode();
final String internalPackageName;
synchronized (mPackages) {
// Normalize package name to handle renamed packages and static libs
- internalPackageName = resolveInternalPackageNameLPr(versionedPackage.getPackageName(),
- versionedPackage.getVersionCode());
+ internalPackageName = resolveInternalPackageNameLPr(packageName, versionCode);
}
final int uid = Binder.getCallingUid();
@@ -16993,24 +17068,24 @@
return pkg.packageName;
}
- private String resolveInternalPackageNameLPr(String packageName, int versionCode) {
+ private String resolveInternalPackageNameLPr(String packageName, long versionCode) {
// Handle renamed packages
String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
packageName = normalizedPackageName != null ? normalizedPackageName : packageName;
// Is this a static library?
- SparseArray<SharedLibraryEntry> versionedLib =
+ LongSparseArray<SharedLibraryEntry> versionedLib =
mStaticLibsByDeclaringPackage.get(packageName);
if (versionedLib == null || versionedLib.size() <= 0) {
return packageName;
}
// Figure out which lib versions the caller can see
- SparseIntArray versionsCallerCanSee = null;
+ LongSparseLongArray versionsCallerCanSee = null;
final int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.SHELL_UID
&& callingAppId != Process.ROOT_UID) {
- versionsCallerCanSee = new SparseIntArray();
+ versionsCallerCanSee = new LongSparseLongArray();
String libName = versionedLib.valueAt(0).info.getName();
String[] uidPackages = getPackagesForUid(Binder.getCallingUid());
if (uidPackages != null) {
@@ -17018,7 +17093,7 @@
PackageSetting ps = mSettings.getPackageLPr(uidPackage);
final int libIdx = ArrayUtils.indexOf(ps.usesStaticLibraries, libName);
if (libIdx >= 0) {
- final int libVersion = ps.usesStaticLibrariesVersions[libIdx];
+ final long libVersion = ps.usesStaticLibrariesVersions[libIdx];
versionsCallerCanSee.append(libVersion, libVersion);
}
}
@@ -17036,10 +17111,10 @@
for (int i = 0; i < versionCount; i++) {
SharedLibraryEntry libEntry = versionedLib.valueAt(i);
if (versionsCallerCanSee != null && versionsCallerCanSee.indexOfKey(
- libEntry.info.getVersion()) < 0) {
+ libEntry.info.getLongVersion()) < 0) {
continue;
}
- final int libVersionCode = libEntry.info.getDeclaringPackage().getVersionCode();
+ final long libVersionCode = libEntry.info.getDeclaringPackage().getLongVersionCode();
if (versionCode != PackageManager.VERSION_CODE_HIGHEST) {
if (libVersionCode == versionCode) {
return libEntry.apk;
@@ -17047,7 +17122,7 @@
} else if (highestVersion == null) {
highestVersion = libEntry;
} else if (libVersionCode > highestVersion.info
- .getDeclaringPackage().getVersionCode()) {
+ .getDeclaringPackage().getLongVersionCode()) {
highestVersion = libEntry;
}
}
@@ -17176,7 +17251,7 @@
* persisting settings for later use
* sending a broadcast if necessary
*/
- int deletePackageX(String packageName, int versionCode, int userId, int deleteFlags) {
+ int deletePackageX(String packageName, long versionCode, int userId, int deleteFlags) {
final PackageRemovedInfo info = new PackageRemovedInfo(this);
final boolean res;
@@ -17227,7 +17302,7 @@
if (!ArrayUtils.isEmpty(libClientPackages)) {
Slog.w(TAG, "Not removing package " + pkg.manifestPackageName
+ " hosting lib " + libEntry.info.getName() + " version "
- + libEntry.info.getVersion() + " used by " + libClientPackages
+ + libEntry.info.getLongVersion() + " used by " + libClientPackages
+ " for user " + currUserId);
return PackageManager.DELETE_FAILED_USED_SHARED_LIBRARY;
}
@@ -17546,21 +17621,30 @@
}
}
- static boolean locationIsPrivileged(File path) {
+ static boolean locationIsPrivileged(String path) {
try {
- final String privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app")
- .getCanonicalPath();
- return path.getCanonicalPath().startsWith(privilegedAppDir);
+ final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
+ final File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app");
+ return path.startsWith(privilegedAppDir.getCanonicalPath())
+ || path.startsWith(privilegedVendorAppDir.getCanonicalPath());
} catch (IOException e) {
Slog.e(TAG, "Unable to access code path " + path);
}
return false;
}
- static boolean locationIsOem(File path) {
+ static boolean locationIsOem(String path) {
try {
- return path.getCanonicalPath().startsWith(
- Environment.getOemDirectory().getCanonicalPath());
+ return path.startsWith(Environment.getOemDirectory().getCanonicalPath());
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to access code path " + path);
+ }
+ return false;
+ }
+
+ static boolean locationIsVendor(String path) {
+ try {
+ return path.startsWith(Environment.getVendorDirectory().getCanonicalPath());
} catch (IOException e) {
Slog.e(TAG, "Unable to access code path " + path);
}
@@ -17656,7 +17740,7 @@
// Install the system package
if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
try {
- installPackageFromSystemLIF(disabledPs.codePath, false /*isPrivileged*/, allUserHandles,
+ installPackageFromSystemLIF(disabledPs.codePathString, false, allUserHandles,
outInfo.origUsers, deletedPs.getPermissionsState(), writeSettings);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to restore system package:" + deletedPkg.packageName + ": "
@@ -17673,7 +17757,7 @@
/**
* Installs a package that's already on the system partition.
*/
- private PackageParser.Package installPackageFromSystemLIF(@NonNull File codePath,
+ private PackageParser.Package installPackageFromSystemLIF(@NonNull String codePathString,
boolean isPrivileged, @Nullable int[] allUserHandles, @Nullable int[] origUserHandles,
@Nullable PermissionsState origPermissionState, boolean writeSettings)
throws PackageManagerException {
@@ -17682,13 +17766,17 @@
| PackageParser.PARSE_MUST_BE_APK
| PackageParser.PARSE_IS_SYSTEM_DIR;
@ScanFlags int scanFlags = SCAN_AS_SYSTEM;
- if (isPrivileged || locationIsPrivileged(codePath)) {
+ if (isPrivileged || locationIsPrivileged(codePathString)) {
scanFlags |= SCAN_AS_PRIVILEGED;
}
- if (locationIsOem(codePath)) {
+ if (locationIsOem(codePathString)) {
scanFlags |= SCAN_AS_OEM;
}
+ if (locationIsVendor(codePathString)) {
+ scanFlags |= SCAN_AS_VENDOR;
+ }
+ final File codePath = new File(codePathString);
final PackageParser.Package pkg =
scanPackageTracedLI(codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
@@ -19800,7 +19888,7 @@
// until we can disable the package later.
enableSystemPackageLPw(deletedPkg);
}
- installPackageFromSystemLIF(new File(deletedPkg.codePath),
+ installPackageFromSystemLIF(deletedPkg.codePath,
false /*isPrivileged*/, null /*allUserHandles*/,
null /*origUserHandles*/, null /*origPermissionsState*/,
true /*writeSettings*/);
@@ -20506,7 +20594,8 @@
final Iterator<String> it = mSharedLibraries.keySet().iterator();
while (it.hasNext()) {
String libName = it.next();
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(libName);
+ LongSparseArray<SharedLibraryEntry> versionedLib
+ = mSharedLibraries.get(libName);
if (versionedLib == null) {
continue;
}
@@ -20526,7 +20615,7 @@
}
pw.print(libEntry.info.getName());
if (libEntry.info.isStatic()) {
- pw.print(" version=" + libEntry.info.getVersion());
+ pw.print(" version=" + libEntry.info.getLongVersion());
}
if (!checkin) {
pw.print(" -> ");
@@ -20895,7 +20984,7 @@
final int count = mSharedLibraries.size();
for (int i = 0; i < count; i++) {
final String libName = mSharedLibraries.keyAt(i);
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(libName);
+ LongSparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(libName);
if (versionedLib == null) {
continue;
}
@@ -22252,6 +22341,11 @@
return mInstallerService;
}
+ @Override
+ public IArtManager getArtManager() {
+ return mArtManagerService;
+ }
+
private boolean userNeedsBadging(int userId) {
int index = mUserNeedsBadging.indexOfKey(userId);
if (index < 0) {
@@ -22400,11 +22494,11 @@
*/
private static void checkDowngrade(PackageParser.Package before, PackageInfoLite after)
throws PackageManagerException {
- if (after.versionCode < before.mVersionCode) {
+ if (after.getLongVersionCode() < before.getLongVersionCode()) {
throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
"Update version code " + after.versionCode + " is older than current "
- + before.mVersionCode);
- } else if (after.versionCode == before.mVersionCode) {
+ + before.getLongVersionCode());
+ } else if (after.getLongVersionCode() == before.getLongVersionCode()) {
if (after.baseRevisionCode < before.baseRevisionCode) {
throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
"Update base revision code " + after.baseRevisionCode
@@ -22591,12 +22685,12 @@
}
@Override
- public int getVersionCodeForPackage(String packageName) throws RemoteException {
+ public long getVersionCodeForPackage(String packageName) throws RemoteException {
try {
int callingUser = UserHandle.getUserId(Binder.getCallingUid());
PackageInfo pInfo = getPackageInfo(packageName, 0, callingUser);
if (pInfo != null) {
- return pInfo.versionCode;
+ return pInfo.getLongVersionCode();
}
} catch (Exception e) {
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 758abd7..20ec9b5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -295,19 +295,20 @@
return false;
}
- public static long getLastModifiedTime(PackageParser.Package pkg, File srcFile) {
- if (srcFile.isDirectory()) {
- final File baseFile = new File(pkg.baseCodePath);
- long maxModifiedTime = baseFile.lastModified();
- if (pkg.splitCodePaths != null) {
- for (int i = pkg.splitCodePaths.length - 1; i >=0; --i) {
- final File splitFile = new File(pkg.splitCodePaths[i]);
- maxModifiedTime = Math.max(maxModifiedTime, splitFile.lastModified());
- }
- }
- return maxModifiedTime;
+ public static long getLastModifiedTime(PackageParser.Package pkg) {
+ final File srcFile = new File(pkg.codePath);
+ if (!srcFile.isDirectory()) {
+ return srcFile.lastModified();
}
- return srcFile.lastModified();
+ final File baseFile = new File(pkg.baseCodePath);
+ long maxModifiedTime = baseFile.lastModified();
+ if (pkg.splitCodePaths != null) {
+ for (int i = pkg.splitCodePaths.length - 1; i >=0; --i) {
+ final File splitFile = new File(pkg.splitCodePaths[i]);
+ maxModifiedTime = Math.max(maxModifiedTime, splitFile.lastModified());
+ }
+ }
+ return maxModifiedTime;
}
/**
@@ -570,7 +571,7 @@
if (!match) {
throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"Package " + packageName +
- " signatures don't match previously installed version; ignoring!");
+ " signatures do not match previously installed version; ignoring!");
}
}
// Check for shared user signatures
@@ -578,16 +579,16 @@
// Already existing package. Make sure signatures match
boolean match = compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
parsedSignatures) == PackageManager.SIGNATURE_MATCH;
- if (!match) {
+ if (!match && compareCompat) {
match = matchSignaturesCompat(
packageName, pkgSetting.sharedUser.signatures, parsedSignatures);
}
- if (!match && compareCompat) {
+ if (!match && compareRecover) {
match = matchSignaturesRecover(
packageName, pkgSetting.sharedUser.signatures.mSignatures, parsedSignatures);
compatMatch |= match;
}
- if (!match && compareRecover) {
+ if (!match) {
throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
"Package " + packageName
+ " has no signatures that match those in shared user "
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 44f36d1..a7cced7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1245,7 +1245,7 @@
final PrintWriter pw = getOutPrintWriter();
int flags = 0;
int userId = UserHandle.USER_ALL;
- int versionCode = PackageManager.VERSION_CODE_HIGHEST;
+ long versionCode = PackageManager.VERSION_CODE_HIGHEST;
String opt;
while ((opt = getNextOption()) != null) {
@@ -1257,7 +1257,7 @@
userId = UserHandle.parseUserArg(getNextArgRequired());
break;
case "--versionCode":
- versionCode = Integer.parseInt(getNextArgRequired());
+ versionCode = Long.parseLong(getNextArgRequired());
break;
default:
pw.println("Error: Unknown option: " + opt);
@@ -1538,13 +1538,26 @@
return 0;
}
+ private boolean isVendorApp(String pkg) {
+ try {
+ final PackageInfo info = mInterface.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
+ return info != null && info.applicationInfo.isVendor();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
private int runGetPrivappPermissions() {
final String pkg = getNextArg();
if (pkg == null) {
getErrPrintWriter().println("Error: no package specified.");
return 1;
}
- ArraySet<String> privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg);
+
+ ArraySet<String> privAppPermissions = isVendorApp(pkg) ?
+ SystemConfig.getInstance().getVendorPrivAppPermissions(pkg)
+ : SystemConfig.getInstance().getPrivAppPermissions(pkg);
+
getOutPrintWriter().println(privAppPermissions == null
? "{}" : privAppPermissions.toString());
return 0;
@@ -1556,10 +1569,13 @@
getErrPrintWriter().println("Error: no package specified.");
return 1;
}
- ArraySet<String> privAppDenyPermissions =
- SystemConfig.getInstance().getPrivAppDenyPermissions(pkg);
- getOutPrintWriter().println(privAppDenyPermissions == null
- ? "{}" : privAppDenyPermissions.toString());
+
+ ArraySet<String> privAppPermissions = isVendorApp(pkg) ?
+ SystemConfig.getInstance().getVendorPrivAppDenyPermissions(pkg)
+ : SystemConfig.getInstance().getPrivAppDenyPermissions(pkg);
+
+ getOutPrintWriter().println(privAppPermissions == null
+ ? "{}" : privAppPermissions.toString());
return 0;
}
@@ -1876,13 +1892,16 @@
final InstallParams params = new InstallParams();
params.sessionParams = sessionParams;
String opt;
+ boolean replaceExisting = true;
while ((opt = getNextOption()) != null) {
switch (opt) {
case "-l":
sessionParams.installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
break;
- case "-r":
- sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
+ case "-r": // ignore
+ break;
+ case "-R":
+ replaceExisting = false;
break;
case "-i":
params.installerPackageName = getNextArg();
@@ -1967,6 +1986,9 @@
default:
throw new IllegalArgumentException("Unknown option " + opt);
}
+ if (replaceExisting) {
+ sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
+ }
}
return params;
}
@@ -2435,7 +2457,7 @@
pw.println(" Install an application. Must provide the apk data to install, either as a");
pw.println(" file path or '-' to read from stdin. Options are:");
pw.println(" -l: forward lock application");
- pw.println(" -r: allow replacement of existing application");
+ pw.println(" -R: disallow replacement of existing application");
pw.println(" -t: allow test packages");
pw.println(" -i: specify package name of installer owning the app");
pw.println(" -s: install application on sdcard");
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 3b414e9..2b91b7d 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -50,9 +50,9 @@
PackageSetting(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString,
- int pVersionCode, int pkgFlags, int privateFlags, String parentPackageName,
+ long pVersionCode, int pkgFlags, int privateFlags, String parentPackageName,
List<String> childPackageNames, int sharedUserId, String[] usesStaticLibraries,
- int[] usesStaticLibrariesVersions) {
+ long[] usesStaticLibrariesVersions) {
super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString,
primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
pVersionCode, pkgFlags, privateFlags, parentPackageName, childPackageNames,
@@ -140,6 +140,10 @@
return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
}
+ public boolean isVendor() {
+ return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
+ }
+
public boolean isForwardLocked() {
return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index a838768..9733624 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -75,7 +75,7 @@
String resourcePathString;
String[] usesStaticLibraries;
- int[] usesStaticLibrariesVersions;
+ long[] usesStaticLibrariesVersions;
/**
* The path under which native libraries have been unpacked. This path is
@@ -105,7 +105,7 @@
long timeStamp;
long firstInstallTime;
long lastUpdateTime;
- int versionCode;
+ long versionCode;
boolean uidError;
@@ -149,9 +149,9 @@
PackageSettingBase(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString,
- int pVersionCode, int pkgFlags, int pkgPrivateFlags,
+ long pVersionCode, int pkgFlags, int pkgPrivateFlags,
String parentPackageName, List<String> childPackageNames,
- String[] usesStaticLibraries, int[] usesStaticLibrariesVersions) {
+ String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) {
super(pkgFlags, pkgPrivateFlags);
this.name = name;
this.realName = realName;
@@ -180,7 +180,7 @@
void init(File codePath, File resourcePath, String legacyNativeLibraryPathString,
String primaryCpuAbiString, String secondaryCpuAbiString,
- String cpuAbiOverrideString, int pVersionCode) {
+ String cpuAbiOverrideString, long pVersionCode) {
this.codePath = codePath;
this.codePathString = codePath.toString();
this.resourcePath = resourcePath;
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index c97f5e5..46ba006 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -61,6 +61,7 @@
this.pkgPrivateFlags = pkgPrivateFlags
& (ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
| ApplicationInfo.PRIVATE_FLAG_OEM
+ | ApplicationInfo.PRIVATE_FLAG_VENDOR
| ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK
| ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER);
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 7077fd1..4a5772f 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -593,10 +593,10 @@
PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
- String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, int vc, int
+ String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, long vc, int
pkgFlags, int pkgPrivateFlags, String parentPackageName,
List<String> childPackageNames, String[] usesStaticLibraries,
- int[] usesStaticLibraryNames) {
+ long[] usesStaticLibraryNames) {
PackageSetting p = mPackages.get(name);
if (p != null) {
if (p.appId == uid) {
@@ -673,11 +673,11 @@
static @NonNull PackageSetting createNewSetting(String pkgName, PackageSetting originalPkg,
PackageSetting disabledPkg, String realPkgName, SharedUserSetting sharedUser,
File codePath, File resourcePath, String legacyNativeLibraryPath, String primaryCpuAbi,
- String secondaryCpuAbi, int versionCode, int pkgFlags, int pkgPrivateFlags,
+ String secondaryCpuAbi, long versionCode, int pkgFlags, int pkgPrivateFlags,
UserHandle installUser, boolean allowInstall, boolean instantApp,
boolean virtualPreload, String parentPkgName, List<String> childPkgNames,
UserManagerService userManager,
- String[] usesStaticLibraries, int[] usesStaticLibrariesVersions) {
+ String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) {
final PackageSetting pkgSetting;
if (originalPkg != null) {
if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
@@ -788,7 +788,7 @@
@Nullable String primaryCpuAbi, @Nullable String secondaryCpuAbi,
int pkgFlags, int pkgPrivateFlags, @Nullable List<String> childPkgNames,
@NonNull UserManagerService userManager, @Nullable String[] usesStaticLibraries,
- @Nullable int[] usesStaticLibrariesVersions) throws PackageManagerException {
+ @Nullable long[] usesStaticLibrariesVersions) throws PackageManagerException {
final String pkgName = pkgSetting.name;
if (pkgSetting.sharedUser != sharedUser) {
PackageManagerService.reportSettingsProblem(Log.WARN,
@@ -847,6 +847,8 @@
pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
pkgSetting.pkgPrivateFlags |=
pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM;
+ pkgSetting.pkgPrivateFlags |=
+ pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR;
pkgSetting.primaryCpuAbiString = primaryCpuAbi;
pkgSetting.secondaryCpuAbiString = secondaryCpuAbi;
if (childPkgNames != null) {
@@ -949,8 +951,8 @@
p.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
p.cpuAbiOverrideString = pkg.cpuAbiOverride;
// Update version code if needed
- if (pkg.mVersionCode != p.versionCode) {
- p.versionCode = pkg.mVersionCode;
+ if (pkg.getLongVersionCode() != p.versionCode) {
+ p.versionCode = pkg.getLongVersionCode();
}
// Update signatures if needed.
if (p.signatures.mSignatures == null) {
@@ -2287,9 +2289,9 @@
String libName = parser.getAttributeValue(null, ATTR_NAME);
String libVersionStr = parser.getAttributeValue(null, ATTR_VERSION);
- int libVersion = -1;
+ long libVersion = -1;
try {
- libVersion = Integer.parseInt(libVersionStr);
+ libVersion = Long.parseLong(libVersionStr);
} catch (NumberFormatException e) {
// ignore
}
@@ -2297,7 +2299,7 @@
if (libName != null && libVersion >= 0) {
outPs.usesStaticLibraries = ArrayUtils.appendElement(String.class,
outPs.usesStaticLibraries, libName);
- outPs.usesStaticLibrariesVersions = ArrayUtils.appendInt(
+ outPs.usesStaticLibrariesVersions = ArrayUtils.appendLong(
outPs.usesStaticLibrariesVersions, libVersion);
}
@@ -2306,7 +2308,7 @@
}
void writeUsesStaticLibLPw(XmlSerializer serializer, String[] usesStaticLibraries,
- int[] usesStaticLibraryVersions) throws IOException {
+ long[] usesStaticLibraryVersions) throws IOException {
if (ArrayUtils.isEmpty(usesStaticLibraries) || ArrayUtils.isEmpty(usesStaticLibraryVersions)
|| usesStaticLibraries.length != usesStaticLibraryVersions.length) {
return;
@@ -2314,10 +2316,10 @@
final int libCount = usesStaticLibraries.length;
for (int i = 0; i < libCount; i++) {
final String libName = usesStaticLibraries[i];
- final int libVersion = usesStaticLibraryVersions[i];
+ final long libVersion = usesStaticLibraryVersions[i];
serializer.startTag(null, TAG_USES_STATIC_LIB);
serializer.attribute(null, ATTR_NAME, libName);
- serializer.attribute(null, ATTR_VERSION, Integer.toString(libVersion));
+ serializer.attribute(null, ATTR_VERSION, Long.toString(libVersion));
serializer.endTag(null, TAG_USES_STATIC_LIB);
}
}
@@ -3561,10 +3563,10 @@
resourcePathStr = codePathStr;
}
String version = parser.getAttributeValue(null, "version");
- int versionCode = 0;
+ long versionCode = 0;
if (version != null) {
try {
- versionCode = Integer.parseInt(version);
+ versionCode = Long.parseLong(version);
} catch (NumberFormatException e) {
}
}
@@ -3572,11 +3574,10 @@
int pkgFlags = 0;
int pkgPrivateFlags = 0;
pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
- final File codePathFile = new File(codePathStr);
- if (PackageManagerService.locationIsPrivileged(codePathFile)) {
+ if (PackageManagerService.locationIsPrivileged(codePathStr)) {
pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
- PackageSetting ps = new PackageSetting(name, realName, codePathFile,
+ PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr),
new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr,
secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags, pkgPrivateFlags,
parentPackageName, null /*childPackageNames*/, 0 /*sharedUserId*/, null, null);
@@ -3678,7 +3679,7 @@
long lastUpdateTime = 0;
PackageSetting packageSetting = null;
String version = null;
- int versionCode = 0;
+ long versionCode = 0;
String parentPackageName;
try {
name = parser.getAttributeValue(null, ATTR_NAME);
@@ -3706,7 +3707,7 @@
version = parser.getAttributeValue(null, "version");
if (version != null) {
try {
- versionCode = Integer.parseInt(version);
+ versionCode = Long.parseLong(version);
} catch (NumberFormatException e) {
}
}
@@ -4422,6 +4423,7 @@
ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, "PRIVILEGED",
ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER, "REQUIRED_FOR_SYSTEM_USER",
ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY, "STATIC_SHARED_LIBRARY",
+ ApplicationInfo.PRIVATE_FLAG_VENDOR, "VENDOR",
ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD, "VIRTUAL_PRELOAD",
};
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index ba97c42..7bab318 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -725,7 +725,7 @@
// This means if a system app's version code doesn't change on an OTA,
// we don't notice it's updated. But that's fine since their version code *should*
// really change on OTAs.
- if ((getPackageInfo().getVersionCode() == pi.versionCode)
+ if ((getPackageInfo().getVersionCode() == pi.getLongVersionCode())
&& (getPackageInfo().getLastUpdateTime() == pi.lastUpdateTime)
&& areAllActivitiesStillEnabled()) {
return false;
@@ -759,11 +759,11 @@
if (ShortcutService.DEBUG) {
Slog.d(TAG, String.format("Package %s %s, version %d -> %d", getPackageName(),
(isNewApp ? "added" : "updated"),
- getPackageInfo().getVersionCode(), pi.versionCode));
+ getPackageInfo().getVersionCode(), pi.getLongVersionCode()));
}
getPackageInfo().updateFromPackageInfo(pi);
- final int newVersionCode = getPackageInfo().getVersionCode();
+ final long newVersionCode = getPackageInfo().getVersionCode();
// See if there are any shortcuts that were prevented restoring because the app was of a
// lower version, and re-enable them.
@@ -1412,7 +1412,7 @@
ShortcutService.writeAttr(out, ATTR_FLAGS, flags);
// Set the publisher version code at every backup.
- final int packageVersionCode = getPackageInfo().getVersionCode();
+ final long packageVersionCode = getPackageInfo().getVersionCode();
if (packageVersionCode == 0) {
s.wtf("Package version code should be available at this point.");
// However, 0 is a valid version code, so we just go ahead with it...
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
index 3a9bbc8..b14e9c9 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
@@ -59,8 +59,8 @@
* been installed yet.
*/
private boolean mIsShadow;
- private int mVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN;
- private int mBackupSourceVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN;
+ private long mVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN;
+ private long mBackupSourceVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN;
private long mLastUpdateTime;
private ArrayList<byte[]> mSigHashes;
@@ -73,7 +73,7 @@
private boolean mBackupAllowed;
private boolean mBackupSourceBackupAllowed;
- private ShortcutPackageInfo(int versionCode, long lastUpdateTime,
+ private ShortcutPackageInfo(long versionCode, long lastUpdateTime,
ArrayList<byte[]> sigHashes, boolean isShadow) {
mVersionCode = versionCode;
mLastUpdateTime = lastUpdateTime;
@@ -96,11 +96,11 @@
mIsShadow = shadow;
}
- public int getVersionCode() {
+ public long getVersionCode() {
return mVersionCode;
}
- public int getBackupSourceVersionCode() {
+ public long getBackupSourceVersionCode() {
return mBackupSourceVersionCode;
}
@@ -123,7 +123,7 @@
*/
public void updateFromPackageInfo(@NonNull PackageInfo pi) {
if (pi != null) {
- mVersionCode = pi.versionCode;
+ mVersionCode = pi.getLongVersionCode();
mLastUpdateTime = pi.lastUpdateTime;
mBackupAllowed = ShortcutService.shouldBackupApp(pi);
mBackupAllowedInitialized = true;
@@ -145,7 +145,7 @@
Slog.w(TAG, "Can't restore: package didn't or doesn't allow backup");
return ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED;
}
- if (!anyVersionOkay && (currentPackage.versionCode < mBackupSourceVersionCode)) {
+ if (!anyVersionOkay && (currentPackage.getLongVersionCode() < mBackupSourceVersionCode)) {
Slog.w(TAG, String.format(
"Can't restore: package current version %d < backed up version %d",
currentPackage.versionCode, mBackupSourceVersionCode));
@@ -162,11 +162,12 @@
Slog.e(TAG, "Can't get signatures: package=" + packageName);
return null;
}
- final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.versionCode, pi.lastUpdateTime,
- BackupUtils.hashSignatureArray(pi.signatures), /* shadow=*/ false);
+ final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.getLongVersionCode(),
+ pi.lastUpdateTime, BackupUtils.hashSignatureArray(pi.signatures),
+ /* shadow=*/ false);
ret.mBackupSourceBackupAllowed = s.shouldBackupApp(pi);
- ret.mBackupSourceVersionCode = pi.versionCode;
+ ret.mBackupSourceVersionCode = pi.getLongVersionCode();
return ret;
}
@@ -213,7 +214,7 @@
throws IOException, XmlPullParserException {
// Don't use the version code from the backup file.
- final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION,
+ final long versionCode = ShortcutService.parseLongAttribute(parser, ATTR_VERSION,
ShortcutInfo.VERSION_CODE_UNKNOWN);
final long lastUpdateTime = ShortcutService.parseLongAttribute(
@@ -225,7 +226,7 @@
// We didn't used to save these attributes, and all backed up shortcuts were from
// apps that support backups, so the default values take this fact into consideration.
- final int backupSourceVersion = ShortcutService.parseIntAttribute(parser,
+ final long backupSourceVersion = ShortcutService.parseLongAttribute(parser,
ATTR_BACKUP_SOURCE_VERSION, ShortcutInfo.VERSION_CODE_UNKNOWN);
// Note the only time these "true" default value is used is when restoring from an old
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index 689099c..0629d9e 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -108,7 +108,7 @@
return; // Not installed, no need to restore yet.
}
int restoreBlockReason;
- int currentVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN;
+ long currentVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN;
if (!mPackageInfo.hasSignatures()) {
s.wtf("Attempted to restore package " + mPackageName + "/u" + mPackageUserId
@@ -116,7 +116,7 @@
restoreBlockReason = ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH;
} else {
final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId);
- currentVersionCode = pi.versionCode;
+ currentVersionCode = pi.getLongVersionCode();
restoreBlockReason = mPackageInfo.canRestoreTo(s, pi, canRestoreAnyVersion());
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 0907dd7..ee2f374 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2739,6 +2739,26 @@
public boolean isRequestPinItemSupported(int callingUserId, int requestType) {
return ShortcutService.this.isRequestPinItemSupported(callingUserId, requestType);
}
+
+ @Override
+ public boolean isForegroundDefaultLauncher(@NonNull String callingPackage, int callingUid) {
+ Preconditions.checkNotNull(callingPackage);
+
+ final int userId = UserHandle.getUserId(callingUid);
+ final ComponentName defaultLauncher = getDefaultLauncher(userId);
+ if (defaultLauncher == null) {
+ return false;
+ }
+ if (!callingPackage.equals(defaultLauncher.getPackageName())) {
+ return false;
+ }
+ synchronized (mLock) {
+ if (!isUidForegroundLocked(callingUid)) {
+ return false;
+ }
+ }
+ return true;
+ }
}
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index dbf413f..dc481ca 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -27,7 +27,6 @@
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerNative;
-import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.IStopUserCallback;
import android.app.KeyguardManager;
@@ -50,6 +49,7 @@
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IProgressListener;
import android.os.IUserManager;
import android.os.Message;
import android.os.ParcelFileDescriptor;
@@ -71,10 +71,6 @@
import android.os.storage.StorageManager;
import android.security.GateKeeper;
import android.service.gatekeeper.IGateKeeperService;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
-import android.text.TextUtils;
import android.util.AtomicFile;
import android.util.IntArray;
import android.util.Log;
@@ -113,9 +109,9 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
@@ -378,22 +374,45 @@
private final BroadcastReceiver mDisableQuietModeCallback = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK.equals(intent.getAction())) {
- final IntentSender target = intent.getParcelableExtra(Intent.EXTRA_INTENT);
- final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_ID, 0);
- setQuietModeEnabled(userHandle, false);
- if (target != null) {
- try {
- mContext.startIntentSender(target, null, 0, 0, 0);
- } catch (IntentSender.SendIntentException e) {
- /* ignore */
- }
- }
+ if (!ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK.equals(intent.getAction())) {
+ return;
}
+ final IntentSender target = intent.getParcelableExtra(Intent.EXTRA_INTENT);
+ final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_NULL);
+ setQuietModeEnabled(userHandle, false, target);
}
};
/**
+ * Start an {@link IntentSender} when user is unlocked after disabling quiet mode.
+ *
+ * @see {@link #trySetQuietModeDisabled(int, IntentSender)}
+ */
+ private class DisableQuietModeUserUnlockedCallback extends IProgressListener.Stub {
+ private final IntentSender mTarget;
+
+ public DisableQuietModeUserUnlockedCallback(IntentSender target) {
+ Preconditions.checkNotNull(target);
+ mTarget = target;
+ }
+
+ @Override
+ public void onStarted(int id, Bundle extras) {}
+
+ @Override
+ public void onProgress(int id, int progress, Bundle extras) {}
+
+ @Override
+ public void onFinished(int id, Bundle extras) {
+ try {
+ mContext.startIntentSender(mTarget, null, 0, 0, 0);
+ } catch (IntentSender.SendIntentException e) {
+ Slog.e(LOG_TAG, "Failed to start the target in the callback", e);
+ }
+ }
+ }
+
+ /**
* Whether all users should be created ephemeral.
*/
@GuardedBy("mUsersLock")
@@ -765,7 +784,7 @@
}
@Override
- public void setQuietModeEnabled(int userHandle, boolean enableQuietMode) {
+ public void setQuietModeEnabled(int userHandle, boolean enableQuietMode, IntentSender target) {
checkManageUsersPermission("silence profile");
boolean changed = false;
UserInfo profile, parent;
@@ -792,7 +811,11 @@
LocalServices.getService(ActivityManagerInternal.class)
.killForegroundAppsForUser(userHandle);
} else {
- ActivityManager.getService().startUserInBackground(userHandle);
+ IProgressListener callback = target != null
+ ? new DisableQuietModeUserUnlockedCallback(target)
+ : null;
+ ActivityManager.getService().startUserInBackgroundWithListener(
+ userHandle, callback);
}
} catch (RemoteException e) {
Slog.e(LOG_TAG, "fail to start/stop user for quiet mode", e);
@@ -820,12 +843,13 @@
}
@Override
- public boolean trySetQuietModeDisabled(int userHandle, IntentSender target) {
+ public boolean trySetQuietModeDisabled(
+ @UserIdInt int userHandle, @Nullable IntentSender target) {
checkManageUsersPermission("silence profile");
if (StorageManager.isUserKeyUnlocked(userHandle)
|| !mLockPatternUtils.isSecure(userHandle)) {
// if the user is already unlocked, no need to show a profile challenge
- setQuietModeEnabled(userHandle, false);
+ setQuietModeEnabled(userHandle, false, target);
return true;
}
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
new file mode 100644
index 0000000..2dbb34d
--- /dev/null
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -0,0 +1,233 @@
+/*
+ * 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.pm.dex;
+
+import android.Manifest;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.dex.ArtManager;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.content.pm.IPackageManager;
+import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.Preconditions;
+import com.android.server.pm.Installer;
+import com.android.server.pm.Installer.InstallerException;
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * A system service that provides access to runtime and compiler artifacts.
+ *
+ * This service is not accessed by users directly, instead one uses an instance of
+ * {@link ArtManager}, which can be accessed via {@link PackageManager} as follows:
+ * <p/>
+ * {@code context().getPackageManager().getArtManager();}
+ * <p class="note">
+ * Note: Accessing runtime artifacts may require extra permissions. For example querying the
+ * runtime profiles of apps requires {@link android.Manifest.permission#READ_RUNTIME_PROFILES}
+ * which is a system-level permission that will not be granted to normal apps.
+ */
+public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
+ private static final String TAG = "ArtManagerService";
+
+ private static boolean DEBUG = false;
+ private static boolean DEBUG_IGNORE_PERMISSIONS = false;
+
+ private final IPackageManager mPackageManager;
+ private final Object mInstallLock;
+ @GuardedBy("mInstallLock")
+ private final Installer mInstaller;
+
+ private final Handler mHandler;
+
+ public ArtManagerService(IPackageManager pm, Installer installer, Object installLock) {
+ mPackageManager = pm;
+ mInstaller = installer;
+ mInstallLock = installLock;
+ mHandler = new Handler(BackgroundThread.getHandler().getLooper());
+ }
+
+ @Override
+ public void snapshotRuntimeProfile(String packageName, String codePath,
+ ISnapshotRuntimeProfileCallback callback) {
+ // Sanity checks on the arguments.
+ Preconditions.checkStringNotEmpty(packageName);
+ Preconditions.checkStringNotEmpty(codePath);
+ Preconditions.checkNotNull(callback);
+
+ // Verify that the caller has the right permissions.
+ checkReadRuntimeProfilePermission();
+
+ if (DEBUG) {
+ Slog.d(TAG, "Requested snapshot for " + packageName + ":" + codePath);
+ }
+
+ PackageInfo info = null;
+ try {
+ // Note that we use the default user 0 to retrieve the package info.
+ // This doesn't really matter because for user 0 we always get a package back (even if
+ // it's not installed for the user 0). It is ok because we only care about the code
+ // paths and not if the package is enabled or not for the user.
+
+ // TODO(calin): consider adding an API to PMS which can retrieve the
+ // PackageParser.Package.
+ info = mPackageManager.getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
+ } catch (RemoteException ignored) {
+ // Should not happen.
+ }
+ if (info == null) {
+ postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_PACKAGE_NOT_FOUND);
+ return;
+ }
+
+ boolean pathFound = info.applicationInfo.getBaseCodePath().equals(codePath);
+ String[] splitCodePaths = info.applicationInfo.getSplitCodePaths();
+ if (!pathFound && (splitCodePaths != null)) {
+ for (String path : splitCodePaths) {
+ if (path.equals(codePath)) {
+ pathFound = true;
+ break;
+ }
+ }
+ }
+ if (!pathFound) {
+ postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND);
+ return;
+ }
+
+ // All good, create the profile snapshot.
+ createProfileSnapshot(packageName, codePath, callback, info);
+ // Destroy the snapshot, we no longer need it.
+ destroyProfileSnapshot(packageName, codePath);
+ }
+
+ private void createProfileSnapshot(String packageName, String codePath,
+ ISnapshotRuntimeProfileCallback callback, PackageInfo info) {
+ // Ask the installer to snapshot the profile.
+ synchronized (mInstallLock) {
+ try {
+ if (!mInstaller.createProfileSnapshot(UserHandle.getAppId(info.applicationInfo.uid),
+ packageName, codePath)) {
+ postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
+ return;
+ }
+ } catch (InstallerException e) {
+ postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
+ return;
+ }
+ }
+
+ // Open the snapshot and invoke the callback.
+ File snapshotProfile = Environment.getProfileSnapshotPath(packageName, codePath);
+ ParcelFileDescriptor fd;
+ try {
+ fd = ParcelFileDescriptor.open(snapshotProfile, ParcelFileDescriptor.MODE_READ_ONLY);
+ postSuccess(packageName, fd, callback);
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "Could not open snapshot profile for " + packageName + ":" + codePath, e);
+ postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
+ }
+ }
+
+ private void destroyProfileSnapshot(String packageName, String codePath) {
+ if (DEBUG) {
+ Slog.d(TAG, "Destroying profile snapshot for" + packageName + ":" + codePath);
+ }
+
+ synchronized (mInstallLock) {
+ try {
+ mInstaller.destroyProfileSnapshot(packageName, codePath);
+ } catch (InstallerException e) {
+ Slog.e(TAG, "Failed to destroy profile snapshot for " +
+ packageName + ":" + codePath, e);
+ }
+ }
+ }
+
+ @Override
+ public boolean isRuntimeProfilingEnabled() {
+ // Verify that the caller has the right permissions.
+ checkReadRuntimeProfilePermission();
+
+ return SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
+ }
+
+ /**
+ * Post {@link ISnapshotRuntimeProfileCallback#onError(int)} with the given error message
+ * on the internal {@code mHandler}.
+ */
+ private void postError(ISnapshotRuntimeProfileCallback callback, String packageName,
+ int errCode) {
+ if (DEBUG) {
+ Slog.d(TAG, "Failed to snapshot profile for " + packageName + " with error: " +
+ errCode);
+ }
+ mHandler.post(() -> {
+ try {
+ callback.onError(errCode);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to callback after profile snapshot for " + packageName, e);
+ }
+ });
+ }
+
+ private void postSuccess(String packageName, ParcelFileDescriptor fd,
+ ISnapshotRuntimeProfileCallback callback) {
+ if (DEBUG) {
+ Slog.d(TAG, "Successfully snapshot profile for " + packageName);
+ }
+ mHandler.post(() -> {
+ try {
+ callback.onSuccess(fd);
+ } catch (RemoteException e) {
+ Slog.w(TAG,
+ "Failed to call onSuccess after profile snapshot for " + packageName, e);
+ }
+ });
+ }
+
+ /**
+ * Verify that the binder calling uid has {@code android.permission.READ_RUNTIME_PROFILE}.
+ * If not, it throws a {@link SecurityException}.
+ */
+ private void checkReadRuntimeProfilePermission() {
+ if (DEBUG_IGNORE_PERMISSIONS) {
+ return;
+ }
+ try {
+ int result = mPackageManager.checkUidPermission(
+ Manifest.permission.READ_RUNTIME_PROFILES, Binder.getCallingUid());
+ if (result != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("You need "
+ + Manifest.permission.READ_RUNTIME_PROFILES
+ + " permission to snapshot profiles.");
+ }
+ } catch (RemoteException e) {
+ // Should not happen.
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index 8c86db6..75a6106 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -225,6 +225,9 @@
public boolean isVerifier() {
return (protectionLevel & PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0;
}
+ public boolean isVendorPrivileged() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_VENDOR_PRIVILEGED) != 0;
+ }
public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) {
if (!origPackageName.equals(sourcePackageName)) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 7d8e206..90ac4ab 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -959,8 +959,9 @@
* <p>This handles parent/child apps.
*/
private boolean hasPrivappWhitelistEntry(String perm, PackageParser.Package pkg) {
- ArraySet<String> wlPermissions = SystemConfig.getInstance()
- .getPrivAppPermissions(pkg.packageName);
+ ArraySet<String> wlPermissions = pkg.isVendor() ?
+ SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.packageName)
+ : SystemConfig.getInstance().getPrivAppPermissions(pkg.packageName);
// Let's check if this package is whitelisted...
boolean whitelisted = wlPermissions != null && wlPermissions.contains(perm);
// If it's not, we'll also tail-recurse to the parent.
@@ -971,7 +972,8 @@
private boolean grantSignaturePermission(String perm, PackageParser.Package pkg,
BasePermission bp, PermissionsState origPermissions) {
boolean oemPermission = bp.isOEM();
- boolean privilegedPermission = bp.isPrivileged();
+ boolean vendorPrivilegedPermission = bp.isVendorPrivileged();
+ boolean privilegedPermission = bp.isPrivileged() || bp.isVendorPrivileged();
boolean privappPermissionsDisable =
RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE;
boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName());
@@ -982,8 +984,11 @@
// Only report violations for apps on system image
if (!mSystemReady && !pkg.isUpdatedSystemApp()) {
// it's only a reportable violation if the permission isn't explicitly denied
- final ArraySet<String> deniedPermissions = SystemConfig.getInstance()
- .getPrivAppDenyPermissions(pkg.packageName);
+ final ArraySet<String> deniedPermissions = pkg.isVendor() ?
+ SystemConfig.getInstance()
+ .getVendorPrivAppDenyPermissions(pkg.packageName)
+ : SystemConfig.getInstance()
+ .getPrivAppDenyPermissions(pkg.packageName);
final boolean permissionViolation =
deniedPermissions == null || !deniedPermissions.contains(perm);
if (permissionViolation) {
@@ -1086,6 +1091,15 @@
|| (oemPermission && pkg.isOem()
&& canGrantOemPermission(ps, perm));
}
+ // In any case, don't grant a privileged permission to privileged vendor apps, if
+ // the permission's protectionLevel does not have the extra 'vendorPrivileged'
+ // flag.
+ if (allowed && privilegedPermission &&
+ !vendorPrivilegedPermission && pkg.isVendor()) {
+ Slog.w(TAG, "Permission " + perm + " cannot be granted to privileged vendor apk "
+ + pkg.packageName + " because it isn't a 'vendorPrivileged' permission.");
+ allowed = false;
+ }
}
}
if (!allowed) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index ddd3bbd..61591bb 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -48,6 +48,7 @@
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA;
import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
@@ -211,6 +212,7 @@
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.IApplicationToken;
@@ -239,12 +241,15 @@
import android.view.inputmethod.InputMethodManagerInternal;
import com.android.internal.R;
+import com.android.internal.accessibility.AccessibilityShortcutController;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
import com.android.internal.policy.PhoneWindow;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ScreenShapeHelper;
import com.android.internal.widget.PointerLocationView;
import com.android.server.GestureLauncherService;
@@ -603,6 +608,8 @@
PointerLocationView mPointerLocationView;
+ boolean mEmulateDisplayCutout = false;
+
// During layout, the layer at which the doc window is placed.
int mDockLayer;
// During layout, this is the layer of the status bar.
@@ -961,6 +968,9 @@
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.POLICY_CONTROL), false, this,
UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.EMULATE_DISPLAY_CUTOUT), false, this,
+ UserHandle.USER_ALL);
updateSettings();
}
@@ -1053,7 +1063,8 @@
private ImmersiveModeConfirmation mImmersiveModeConfirmation;
- private SystemGesturesPointerEventListener mSystemGestures;
+ @VisibleForTesting
+ SystemGesturesPointerEventListener mSystemGestures;
IStatusBarService getStatusBarService() {
synchronized (mServiceAquireLock) {
@@ -2391,6 +2402,10 @@
if (mImmersiveModeConfirmation != null) {
mImmersiveModeConfirmation.loadSetting(mCurrentUserId);
}
+ mEmulateDisplayCutout = Settings.Global.getInt(resolver,
+ Settings.Global.EMULATE_DISPLAY_CUTOUT,
+ Settings.Global.EMULATE_DISPLAY_CUTOUT_OFF)
+ != Settings.Global.EMULATE_DISPLAY_CUTOUT_OFF;
}
synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
PolicyControl.reloadFromSetting(mContext);
@@ -2664,17 +2679,21 @@
// The status bar is the only window allowed to exhibit keyguard behavior.
attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
}
+ }
+ private int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
+ int impliedFlags = 0;
if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
- attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+ impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
}
final boolean forceWindowDrawsStatusBarBackground =
(attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
|| forceWindowDrawsStatusBarBackground
&& attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT) {
- attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+ impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
}
+ return impliedFlags;
}
void readLidState() {
@@ -2724,7 +2743,7 @@
@Override
public void onConfigurationChanged() {
// TODO(multi-display): Define policy for secondary displays.
- Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
+ Context uiContext = getSystemUiContext();
final Resources res = uiContext.getResources();
mStatusBarHeight =
@@ -2765,6 +2784,11 @@
}
}
+ @VisibleForTesting
+ Context getSystemUiContext() {
+ return ActivityThread.currentActivityThread().getSystemUiContext();
+ }
+
@Override
public int getMaxWallpaperLayer() {
return getWindowLayerFromTypeLw(TYPE_STATUS_BAR);
@@ -3368,7 +3392,7 @@
}
boolean keyguardOn() {
- return isKeyguardShowingAndNotOccluded() || inKeyguardRestrictedKeyInputMode();
+ return isKeyguardShowingAndNotOccluded();
}
private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = {
@@ -4324,7 +4348,7 @@
// TODO: Should probably be moved into DisplayFrames.
public boolean getInsetHintLw(WindowManager.LayoutParams attrs, Rect taskBounds,
DisplayFrames displayFrames, Rect outContentInsets, Rect outStableInsets,
- Rect outOutsets) {
+ Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout) {
final int fl = PolicyControl.getWindowFlags(null, attrs);
final int sysuiVis = PolicyControl.getSystemUiVisibility(null, attrs);
final int systemUiVisibility = (sysuiVis | attrs.subtreeSystemUiVisibility);
@@ -4350,12 +4374,15 @@
if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
== (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
+ Rect frame;
int availRight, availBottom;
if (canHideNavigationBar() &&
(systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
+ frame = displayFrames.mUnrestricted;
availRight = displayFrames.mUnrestricted.right;
availBottom = displayFrames.mUnrestricted.bottom;
} else {
+ frame = displayFrames.mRestricted;
availRight = displayFrames.mRestricted.right;
availBottom = displayFrames.mRestricted.bottom;
}
@@ -4386,10 +4413,12 @@
calculateRelevantTaskInsets(taskBounds, outStableInsets,
displayWidth, displayHeight);
}
+ outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(frame));
return mForceShowSystemBars;
}
outContentInsets.setEmpty();
outStableInsets.setEmpty();
+ outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
return mForceShowSystemBars;
}
@@ -4417,7 +4446,7 @@
/** {@inheritDoc} */
@Override
public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
- displayFrames.onBeginLayout();
+ displayFrames.onBeginLayout(mEmulateDisplayCutout, mStatusBarHeight);
// TODO(multi-display): This doesn't seem right...Maybe only apply to default display?
mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
@@ -4487,6 +4516,14 @@
}
}
layoutScreenDecorWindows(displayFrames, pf, df, dcf);
+
+ if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
+ // Make sure that the zone we're avoiding for the cutout is at least as tall as the
+ // status bar; otherwise fullscreen apps will end up cutting halfway into the status
+ // bar.
+ displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top,
+ displayFrames.mStable.top);
+ }
}
private void layoutScreenDecorWindows(DisplayFrames displayFrames, Rect pf, Rect df, Rect dcf) {
@@ -4508,7 +4545,7 @@
w.computeFrameLw(pf /* parentFrame */, df /* displayFrame */, df /* overlayFrame */,
df /* contentFrame */, df /* visibleFrame */, dcf /* decorFrame */,
- df /* stableFrame */, df /* outsetFrame */);
+ df /* stableFrame */, df /* outsetFrame */, displayFrames.mDisplayCutout);
final Rect frame = w.getFrameLw();
if (frame.left <= 0 && frame.top <= 0) {
@@ -4570,7 +4607,8 @@
// Let the status bar determine its size.
mStatusBar.computeFrameLw(pf /* parentFrame */, df /* displayFrame */,
vf /* overlayFrame */, vf /* contentFrame */, vf /* visibleFrame */,
- dcf /* decorFrame */, vf /* stableFrame */, vf /* outsetFrame */);
+ dcf /* decorFrame */, vf /* stableFrame */, vf /* outsetFrame */,
+ displayFrames.mDisplayCutout);
// For layout, the status bar is always at the top with our fixed height.
displayFrames.mStable.top = displayFrames.mUnrestricted.top + mStatusBarHeight;
@@ -4621,11 +4659,15 @@
final Rect dockFrame = displayFrames.mDock;
mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
+ final Rect cutoutSafeUnrestricted = mTmpRect;
+ cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
+ cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
+
if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
// It's a system nav bar or a portrait screen; nav bar goes on bottom.
- final int top = displayFrames.mUnrestricted.bottom
+ final int top = cutoutSafeUnrestricted.bottom
- getNavigationBarHeight(rotation, uiMode);
- mTmpNavigationFrame.set(0, top, displayWidth, displayFrames.mUnrestricted.bottom);
+ mTmpNavigationFrame.set(0, top, displayWidth, cutoutSafeUnrestricted.bottom);
displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top;
if (transientNavBarShowing) {
mNavigationBarController.setBarShowingLw(true);
@@ -4646,9 +4688,9 @@
}
} else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
// Landscape screen; nav bar goes to the right.
- final int left = displayFrames.mUnrestricted.right
+ final int left = cutoutSafeUnrestricted.right
- getNavigationBarWidth(rotation, uiMode);
- mTmpNavigationFrame.set(left, 0, displayFrames.mUnrestricted.right, displayHeight);
+ mTmpNavigationFrame.set(left, 0, cutoutSafeUnrestricted.right, displayHeight);
displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left;
if (transientNavBarShowing) {
mNavigationBarController.setBarShowingLw(true);
@@ -4669,9 +4711,9 @@
}
} else if (mNavigationBarPosition == NAV_BAR_LEFT) {
// Seascape screen; nav bar goes to the left.
- final int right = displayFrames.mUnrestricted.left
+ final int right = cutoutSafeUnrestricted.left
+ getNavigationBarWidth(rotation, uiMode);
- mTmpNavigationFrame.set(displayFrames.mUnrestricted.left, 0, right, displayHeight);
+ mTmpNavigationFrame.set(cutoutSafeUnrestricted.left, 0, right, displayHeight);
displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right;
if (transientNavBarShowing) {
mNavigationBarController.setBarShowingLw(true);
@@ -4701,7 +4743,7 @@
// And compute the final frame.
mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, dcf,
- mTmpNavigationFrame, mTmpNavigationFrame);
+ mTmpNavigationFrame, mTmpNavigationFrame, displayFrames.mDisplayCutout);
if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
return mNavigationBarController.checkHiddenLw();
}
@@ -4823,9 +4865,11 @@
final int type = attrs.type;
final int fl = PolicyControl.getWindowFlags(win, attrs);
+ final long fl2 = attrs.flags2;
final int pfl = attrs.privateFlags;
final int sim = attrs.softInputMode;
- final int sysUiFl = PolicyControl.getSystemUiVisibility(win, null);
+ final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(win, null);
+ final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
final Rect pf = mTmpParentFrame;
final Rect df = mTmpDisplayFrame;
@@ -4842,6 +4886,14 @@
final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
+ final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
+ || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0
+ || (requestedSysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0;
+
+ final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
+ final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
+ final boolean layoutInCutout = (fl2 & FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA) != 0;
+
sf.set(displayFrames.mStable);
if (type == TYPE_INPUT_METHOD) {
@@ -4851,7 +4903,8 @@
df.set(displayFrames.mDock);
pf.set(displayFrames.mDock);
// IM dock windows layout below the nav bar...
- pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom;
+ pf.bottom = df.bottom = of.bottom = Math.min(displayFrames.mUnrestricted.bottom,
+ displayFrames.mDisplayCutoutSafe.bottom);
// ...with content insets above the nav bar
cf.bottom = vf.bottom = displayFrames.mStable.bottom;
if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
@@ -4922,8 +4975,7 @@
}
}
- if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
- == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
+ if (layoutInScreen && layoutInsetDecor) {
if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
+ "): IN_SCREEN, INSET_DECOR");
// This is the case for a normal activity window: we want it to cover all of the
@@ -5000,6 +5052,9 @@
// moving from a window that is not hiding the status bar to one that is.
cf.set(displayFrames.mRestricted);
}
+ if (requestedFullscreen && !layoutInCutout) {
+ pf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
+ }
applyStableConstraints(sysUiFl, fl, cf, displayFrames);
if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
vf.set(displayFrames.mCurrent);
@@ -5007,7 +5062,7 @@
vf.set(cf);
}
}
- } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0 || (sysUiFl
+ } else if (layoutInScreen || (sysUiFl
& (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
@@ -5085,6 +5140,9 @@
of.set(displayFrames.mUnrestricted);
df.set(displayFrames.mUnrestricted);
pf.set(displayFrames.mUnrestricted);
+ if (requestedFullscreen && !layoutInCutout) {
+ pf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
+ }
} else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
of.set(displayFrames.mRestricted);
df.set(displayFrames.mRestricted);
@@ -5155,9 +5213,27 @@
vf.set(cf);
}
}
+ pf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
}
}
+ // Ensure that windows that did not request to be laid out in the cutout don't get laid
+ // out there.
+ if (!layoutInCutout) {
+ final Rect displayCutoutSafeExceptMaybeTop = mTmpRect;
+ displayCutoutSafeExceptMaybeTop.set(displayFrames.mDisplayCutoutSafe);
+ if (layoutInScreen && layoutInsetDecor) {
+ // At the top we have the status bar, so apps that are
+ // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR already expect that there's an inset
+ // there and we don't need to exclude the window from that area.
+ displayCutoutSafeExceptMaybeTop.top = Integer.MIN_VALUE;
+ }
+ pf.intersectUnchecked(displayCutoutSafeExceptMaybeTop);
+ }
+
+ // Content should never appear in the cutout.
+ cf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
+
// TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
// Also, we don't allow windows in multi-window mode to extend out of the screen.
if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR
@@ -5206,7 +5282,7 @@
+ " sf=" + sf.toShortString()
+ " osf=" + (osf == null ? "null" : osf.toShortString()));
- win.computeFrameLw(pf, df, of, cf, vf, dcf, sf, osf);
+ win.computeFrameLw(pf, df, of, cf, vf, dcf, sf, osf, displayFrames.mDisplayCutout);
// Dock windows carve out the bottom of the screen, so normal windows
// can't appear underneath them.
@@ -6858,13 +6934,6 @@
return mKeyguardOccluded;
}
- /** {@inheritDoc} */
- @Override
- public boolean inKeyguardRestrictedKeyInputMode() {
- if (mKeyguardDelegate == null) return false;
- return mKeyguardDelegate.isInputRestricted();
- }
-
@Override
public void dismissKeyguardLw(IKeyguardDismissCallback callback) {
if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
@@ -7201,15 +7270,7 @@
}
static long[] getLongIntArray(Resources r, int resid) {
- int[] ar = r.getIntArray(resid);
- if (ar == null) {
- return null;
- }
- long[] out = new long[ar.length];
- for (int i=0; i<ar.length; i++) {
- out[i] = ar[i];
- }
- return out;
+ return ArrayUtils.convertToLongArray(r.getIntArray(resid));
}
private void bindKeyguard() {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 8d56eb8..bcb7212 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -77,6 +77,7 @@
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.IApplicationToken;
import android.view.IWindowManager;
import android.view.InputEventReceiver;
@@ -210,10 +211,11 @@
* @param stableFrame The frame around which stable system decoration is positioned.
* @param outsetFrame The frame that includes areas that aren't part of the surface but we
* want to treat them as such.
+ * @param displayCutout the display displayCutout
*/
public void computeFrameLw(Rect parentFrame, Rect displayFrame,
Rect overlayFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame,
- Rect stableFrame, Rect outsetFrame);
+ Rect stableFrame, @Nullable Rect outsetFrame, DisplayCutout displayCutout);
/**
* Retrieve the current frame of the window that has been assigned by
@@ -808,11 +810,11 @@
case TYPE_INPUT_METHOD_DIALOG:
// on-screen keyboards and other such input method user interfaces go here.
return 15;
- case TYPE_STATUS_BAR_SUB_PANEL:
- return 17;
case TYPE_STATUS_BAR:
- return 18;
+ return 17;
case TYPE_STATUS_BAR_PANEL:
+ return 18;
+ case TYPE_STATUS_BAR_SUB_PANEL:
return 19;
case TYPE_KEYGUARD_DIALOG:
return 20;
@@ -1144,12 +1146,13 @@
* @param outStableInsets The areas covered by stable system windows irrespective of their
* current visibility. Expressed as positive insets.
* @param outOutsets The areas that are not real display, but we would like to treat as such.
+ * @param outDisplayCutout The area that has been cut away from the display.
* @return Whether to always consume the navigation bar.
* See {@link #isNavBarForcedShownLw(WindowState)}.
*/
default boolean getInsetHintLw(WindowManager.LayoutParams attrs, Rect taskBounds,
DisplayFrames displayFrames, Rect outContentInsets, Rect outStableInsets,
- Rect outOutsets) {
+ Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout) {
return false;
}
@@ -1357,17 +1360,6 @@
public boolean isKeyguardTrustedLw();
/**
- * inKeyguardRestrictedKeyInputMode
- *
- * if keyguard screen is showing or in restricted key input mode (i.e. in
- * keyguard password emergency screen). When in such mode, certain keys,
- * such as the Home key and the right soft keys, don't work.
- *
- * @return true if in keyguard restricted input mode.
- */
- public boolean inKeyguardRestrictedKeyInputMode();
-
- /**
* Ask the policy to dismiss the keyguard, if it is currently shown.
*
* @param callback Callback to be informed about the result.
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 87c9274..6f005a3 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -49,11 +49,21 @@
public static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE.
- // Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode.
+ /** Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode. */
public static final int GPS_MODE_NO_CHANGE = 0;
- // Value of batterySaverGpsMode such that GPS is disabled when battery saver mode
- // is enabled and the screen is off.
+
+ /**
+ * Value of batterySaverGpsMode such that GPS is disabled when battery saver mode
+ * is enabled and the screen is off.
+ */
public static final int GPS_MODE_DISABLED_WHEN_SCREEN_OFF = 1;
+
+ /**
+ * Value of batterySaverGpsMode such that location should be disabled altogether
+ * when battery saver mode is enabled and the screen is off.
+ */
+ public static final int GPS_MODE_ALL_DISABLED_WHEN_SCREEN_OFF = 2;
+
// Secure setting for GPS behavior when battery saver mode is on.
public static final String SECURE_KEY_GPS_MODE = "batterySaverGpsMode";
@@ -69,6 +79,7 @@
private static final String KEY_FULLBACKUP_DEFERRED = "fullbackup_deferred";
private static final String KEY_KEYVALUE_DEFERRED = "keyvaluebackup_deferred";
private static final String KEY_FORCE_ALL_APPS_STANDBY = "force_all_apps_standby";
+ private static final String KEY_FORCE_BACKGROUND_CHECK = "force_background_check";
private static final String KEY_OPTIONAL_SENSORS_DISABLED = "optional_sensors_disabled";
private static final String KEY_CPU_FREQ_INTERACTIVE = "cpufreq-i";
@@ -86,6 +97,12 @@
private String mDeviceSpecificSettingsSource; // For dump() only.
/**
+ * A short string describing which battery saver is now enabled, which we dump in the eventlog.
+ */
+ @GuardedBy("mLock")
+ private String mEventLogKeys;
+
+ /**
* {@code true} if vibration is disabled in battery saver mode.
*
* @see Settings.Global#BATTERY_SAVER_CONSTANTS
@@ -190,6 +207,12 @@
private boolean mForceAllAppsStandby;
/**
+ * Whether to put all apps in the stand-by mode.
+ */
+ @GuardedBy("mLock")
+ private boolean mForceBackgroundCheck;
+
+ /**
* Weather to show non-essential sensors (e.g. edge sensors) or not.
*/
@GuardedBy("mLock")
@@ -316,21 +339,22 @@
}
mVibrationDisabled = parser.getBoolean(KEY_VIBRATION_DISABLED, true);
- mAnimationDisabled = parser.getBoolean(KEY_ANIMATION_DISABLED, true);
+ mAnimationDisabled = parser.getBoolean(KEY_ANIMATION_DISABLED, false);
mSoundTriggerDisabled = parser.getBoolean(KEY_SOUNDTRIGGER_DISABLED, true);
mFullBackupDeferred = parser.getBoolean(KEY_FULLBACKUP_DEFERRED, true);
mKeyValueBackupDeferred = parser.getBoolean(KEY_KEYVALUE_DEFERRED, true);
mFireWallDisabled = parser.getBoolean(KEY_FIREWALL_DISABLED, false);
- mAdjustBrightnessDisabled = parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED, false);
+ mAdjustBrightnessDisabled = parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED, true);
mAdjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR, 0.5f);
mDataSaverDisabled = parser.getBoolean(KEY_DATASAVER_DISABLED, true);
mLaunchBoostDisabled = parser.getBoolean(KEY_LAUNCH_BOOST_DISABLED, true);
mForceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY, true);
+ mForceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK, true);
mOptionalSensorsDisabled = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED, true);
// Get default value from Settings.Secure
final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE,
- GPS_MODE_NO_CHANGE);
+ GPS_MODE_ALL_DISABLED_WHEN_SCREEN_OFF);
mGpsMode = parser.getInt(KEY_GPS_MODE, defaultGpsMode);
// Non-device-specific parameters.
@@ -346,6 +370,27 @@
mFilesForNoninteractive = (new CpuFrequencies()).parseString(
parser.getString(KEY_CPU_FREQ_NONINTERACTIVE, "")).toSysFileMap();
+
+ final StringBuilder sb = new StringBuilder();
+
+ if (mForceAllAppsStandby) sb.append("A");
+ if (mForceBackgroundCheck) sb.append("B");
+
+ if (mVibrationDisabled) sb.append("v");
+ if (mAnimationDisabled) sb.append("a");
+ if (mSoundTriggerDisabled) sb.append("s");
+ if (mFullBackupDeferred) sb.append("F");
+ if (mKeyValueBackupDeferred) sb.append("K");
+ if (!mFireWallDisabled) sb.append("f");
+ if (!mDataSaverDisabled) sb.append("d");
+ if (!mAdjustBrightnessDisabled) sb.append("b");
+
+ if (mLaunchBoostDisabled) sb.append("l");
+ if (mOptionalSensorsDisabled) sb.append("S");
+
+ sb.append(mGpsMode);
+
+ mEventLogKeys = sb.toString();
}
/**
@@ -395,6 +440,12 @@
case ServiceType.VIBRATION:
return builder.setBatterySaverEnabled(mVibrationDisabled)
.build();
+ case ServiceType.FORCE_ALL_APPS_STANDBY:
+ return builder.setBatterySaverEnabled(mForceAllAppsStandby)
+ .build();
+ case ServiceType.FORCE_BACKGROUND_CHECK:
+ return builder.setBatterySaverEnabled(mForceBackgroundCheck)
+ .build();
case ServiceType.OPTIONAL_SENSORS:
return builder.setBatterySaverEnabled(mOptionalSensorsDisabled)
.build();
@@ -405,6 +456,12 @@
}
}
+ public int getGpsMode() {
+ synchronized (mLock) {
+ return mGpsMode;
+ }
+ }
+
public ArrayMap<String, String> getFileValues(boolean interactive) {
synchronized (mLock) {
return interactive ? mFilesForInteractive : mFilesForNoninteractive;
@@ -417,6 +474,12 @@
}
}
+ public String toEventLogString() {
+ synchronized (mLock) {
+ return mEventLogKeys;
+ }
+ }
+
public void dump(PrintWriter pw) {
synchronized (mLock) {
pw.println();
@@ -438,6 +501,7 @@
pw.println(" " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mAdjustBrightnessFactor);
pw.println(" " + KEY_GPS_MODE + "=" + mGpsMode);
pw.println(" " + KEY_FORCE_ALL_APPS_STANDBY + "=" + mForceAllAppsStandby);
+ pw.println(" " + KEY_FORCE_BACKGROUND_CHECK + "=" + mForceBackgroundCheck);
pw.println(" " + KEY_OPTIONAL_SENSORS_DISABLED + "=" + mOptionalSensorsDisabled);
pw.println();
diff --git a/services/core/java/com/android/server/power/OWNERS b/services/core/java/com/android/server/power/OWNERS
index b4300a9..d118c4e 100644
--- a/services/core/java/com/android/server/power/OWNERS
+++ b/services/core/java/com/android/server/power/OWNERS
@@ -1,3 +1,4 @@
michaelwr@google.com
per-file BatterySaverPolicy.java=omakoto@google.com
+per-file ShutdownThread.java=fkupolov@google.com
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 6bf725e..6fb345b 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -20,10 +20,7 @@
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.IActivityManager;
-import android.app.KeyguardManager;
import android.app.ProgressDialog;
-import android.app.WallpaperColors;
-import android.app.WallpaperManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.IBluetoothManager;
import android.content.BroadcastReceiver;
@@ -31,8 +28,6 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
import android.media.AudioAttributes;
import android.os.FileUtils;
import android.os.Handler;
@@ -47,8 +42,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
-import android.os.storage.IStorageManager;
-import android.os.storage.IStorageShutdownObserver;
import android.util.ArrayMap;
import android.util.Log;
import android.util.TimingsTraceLog;
@@ -123,7 +116,6 @@
private static String METRIC_RADIOS = "shutdown_radios";
private static String METRIC_BT = "shutdown_bt";
private static String METRIC_RADIO = "shutdown_radio";
- private static String METRIC_SM = "shutdown_storage_manager";
private final Object mActionDoneSync = new Object();
private boolean mActionDone;
@@ -526,54 +518,6 @@
shutdownTimingLog.traceEnd(); // ShutdownRadios
metricEnded(METRIC_RADIOS);
- // Shutdown StorageManagerService to ensure media is in a safe state
- IStorageShutdownObserver observer = new IStorageShutdownObserver.Stub() {
- public void onShutDownComplete(int statusCode) throws RemoteException {
- Log.w(TAG, "Result code " + statusCode + " from StorageManagerService.shutdown");
- actionDone();
- }
- };
-
- Log.i(TAG, "Shutting down StorageManagerService");
- shutdownTimingLog.traceBegin("ShutdownStorageManager");
- metricStarted(METRIC_SM);
-
- // Set initial variables and time out time.
- mActionDone = false;
- final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
- synchronized (mActionDoneSync) {
- try {
- final IStorageManager storageManager = IStorageManager.Stub.asInterface(
- ServiceManager.checkService("mount"));
- if (storageManager != null) {
- storageManager.shutdown(observer);
- } else {
- Log.w(TAG, "StorageManagerService unavailable for shutdown");
- }
- } catch (Exception e) {
- Log.e(TAG, "Exception during StorageManagerService shutdown", e);
- }
- while (!mActionDone) {
- long delay = endShutTime - SystemClock.elapsedRealtime();
- if (delay <= 0) {
- Log.w(TAG, "StorageManager shutdown wait timed out");
- break;
- } else if (mRebootHasProgressBar) {
- int status = (int)((MAX_SHUTDOWN_WAIT_TIME - delay) * 1.0 *
- (MOUNT_SERVICE_STOP_PERCENT - RADIO_STOP_PERCENT) /
- MAX_SHUTDOWN_WAIT_TIME);
- status += RADIO_STOP_PERCENT;
- sInstance.setRebootProgress(status, null);
- }
- try {
- mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS));
- } catch (InterruptedException e) {
- }
- }
- }
- shutdownTimingLog.traceEnd(); // ShutdownStorageManager
- metricEnded(METRIC_SM);
-
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);
@@ -585,6 +529,7 @@
shutdownTimingLog.traceEnd(); // SystemServerShutdown
metricEnded(METRIC_SYSTEM_SERVER);
saveMetrics(mReboot);
+ // Remaining work will be done by init, including vold shutdown
rebootOrShutdown(mContext, mReboot, mReason);
}
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index ae01ea57..d4627c2 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -16,11 +16,18 @@
package com.android.server.power.batterysaver;
import android.Manifest;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.Notification;
+import android.app.Notification.BigTextStyle;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.power.V1_0.PowerHint;
+import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -31,11 +38,14 @@
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;
-import android.widget.Toast;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
+import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.power.BatterySaverPolicy;
import com.android.server.power.BatterySaverPolicy.BatterySaverPolicyListener;
@@ -60,12 +70,37 @@
private final BatterySaverPolicy mBatterySaverPolicy;
+ private static final String WARNING_LINK_URL = "http://goto.google.com/extreme-battery-saver";
+
@GuardedBy("mLock")
private final ArrayList<LowPowerModeListener> mListeners = new ArrayList<>();
@GuardedBy("mLock")
private boolean mEnabled;
+ /**
+ * Previously enabled or not; only for the event logging. Only use it from
+ * {@link #handleBatterySaverStateChanged}.
+ */
+ private boolean mPreviouslyEnabled;
+
+ @GuardedBy("mLock")
+ private boolean mIsInteractive;
+
+ /**
+ * Read-only list of plugins. No need for synchronization.
+ */
+ private final Plugin[] mPlugins;
+
+ /**
+ * Plugin interface. All methods are guaranteed to be called on the same (handler) thread.
+ */
+ public interface Plugin {
+ void onSystemReady(BatterySaverController caller);
+
+ void onBatterySaverChanged(BatterySaverController caller);
+ }
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -91,6 +126,12 @@
mBatterySaverPolicy = policy;
mBatterySaverPolicy.addListener(this);
mFileUpdater = new FileUpdater(context);
+
+ // Initialize plugins.
+ final ArrayList<Plugin> plugins = new ArrayList<>();
+ plugins.add(new BatterySaverLocationPlugin(mContext));
+
+ mPlugins = plugins.toArray(new Plugin[plugins.size()]);
}
/**
@@ -103,12 +144,16 @@
}
/**
- * Called by {@link PowerManagerService} on system ready..
+ * Called by {@link PowerManagerService} on system ready.
*/
public void systemReady() {
final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
mContext.registerReceiver(mReceiver, filter);
+
+ mFileUpdater.systemReady(LocalServices.getService(ActivityManagerInternal.class)
+ .isRuntimeRestarted());
+ mHandler.postSystemReady();
}
private PowerManager getPowerManager() {
@@ -133,6 +178,8 @@
private static final int ARG_DONT_SEND_BROADCAST = 0;
private static final int ARG_SEND_BROADCAST = 1;
+ private static final int MSG_SYSTEM_READY = 2;
+
public MyHandler(Looper looper) {
super(looper);
}
@@ -142,12 +189,22 @@
ARG_SEND_BROADCAST : ARG_DONT_SEND_BROADCAST, 0).sendToTarget();
}
+ public void postSystemReady() {
+ obtainMessage(MSG_SYSTEM_READY, 0, 0).sendToTarget();
+ }
+
@Override
public void dispatchMessage(Message msg) {
switch (msg.what) {
case MSG_STATE_CHANGED:
handleBatterySaverStateChanged(msg.arg1 == ARG_SEND_BROADCAST);
break;
+
+ case MSG_SYSTEM_READY:
+ for (Plugin p : mPlugins) {
+ p.onSystemReady(BatterySaverController.this);
+ }
+ break;
}
}
}
@@ -167,12 +224,24 @@
}
/** @return whether battery saver is enabled or not. */
- boolean isEnabled() {
+ public boolean isEnabled() {
synchronized (mLock) {
return mEnabled;
}
}
+ /** @return whether device is in interactive state. */
+ public boolean isInteractive() {
+ synchronized (mLock) {
+ return mIsInteractive;
+ }
+ }
+
+ /** @return Battery saver policy. */
+ public BatterySaverPolicy getBatterySaverPolicy() {
+ return mBatterySaverPolicy;
+ }
+
/**
* @return true if launch boost should currently be disabled.
*/
@@ -199,11 +268,18 @@
final ArrayMap<String, String> fileValues;
synchronized (mLock) {
- Slog.i(TAG, "Battery saver " + (mEnabled ? "enabled" : "disabled")
- + ": isInteractive=" + isInteractive);
+ EventLogTags.writeBatterySaverMode(
+ mPreviouslyEnabled ? 1 : 0, // Previously off or on.
+ mEnabled ? 1 : 0, // Now off or on.
+ isInteractive ? 1 : 0, // Device interactive state.
+ mEnabled ? mBatterySaverPolicy.toEventLogString() : "");
+ mPreviouslyEnabled = mEnabled;
listeners = mListeners.toArray(new LowPowerModeListener[mListeners.size()]);
+
enabled = mEnabled;
+ mIsInteractive = isInteractive;
+
if (enabled) {
fileValues = mBatterySaverPolicy.getFileValues(isInteractive);
@@ -217,20 +293,24 @@
pmi.powerHint(PowerHint.LOW_POWER, enabled ? 1 : 0);
}
- if (enabled) {
- // STOPSHIP Remove the toast.
- Toast.makeText(mContext,
- com.android.internal.R.string.battery_saver_warning,
- Toast.LENGTH_LONG).show();
- }
-
if (ArrayUtils.isEmpty(fileValues)) {
mFileUpdater.restoreDefault();
} else {
mFileUpdater.writeFiles(fileValues);
}
+ for (Plugin p : mPlugins) {
+ p.onBatterySaverChanged(this);
+ }
+
if (sendBroadcast) {
+ if (enabled) {
+ // STOPSHIP Remove the toast.
+ postWarningNotification();
+ } else {
+ cancelWarningNotification();
+ }
+
if (DEBUG) {
Slog.i(TAG, "Sending broadcasts for mode: " + enabled);
}
@@ -261,4 +341,51 @@
}
}
}
+
+ private void postWarningNotification() {
+ final UserHandle foregroundUser = UserHandle.of(ActivityManager.getCurrentUser());
+
+ final PendingIntent pendingIntent = PendingIntent
+ .getActivityAsUser(mContext, 0,
+ new Intent(Intent.ACTION_VIEW, Uri.parse(WARNING_LINK_URL)),
+ PendingIntent.FLAG_CANCEL_CURRENT, null,
+ foregroundUser);
+
+ final CharSequence title = mContext.getString
+ (com.android.internal.R.string.battery_saver_warning_title);
+ final CharSequence text = mContext.getString
+ (com.android.internal.R.string.battery_saver_warning);
+
+ final Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.ALERTS)
+ .setSmallIcon(R.drawable.stat_notify_error)
+ .setTicker(title)
+ .setWhen(System.currentTimeMillis())
+ .setContentTitle(title)
+ .setContentText(text)
+ .setContentIntent(pendingIntent)
+ .setStyle(new BigTextStyle().bigText(text))
+ .build();
+
+ final NotificationManager nm = mContext.getSystemService(NotificationManager.class);
+
+ if (nm != null) {
+ nm.notifyAsUser(title.toString(),
+ SystemMessage.NOTE_BATTERY_SAVER_WARNING,
+ notification,
+ foregroundUser);
+ }
+ }
+
+ private void cancelWarningNotification() {
+ final UserHandle foregroundUser = UserHandle.of(ActivityManager.getCurrentUser());
+ final CharSequence title = mContext.getString
+ (com.android.internal.R.string.battery_saver_warning_title);
+
+ final NotificationManager nm = mContext.getSystemService(NotificationManager.class);
+ if (nm != null) {
+ nm.cancelAsUser(title.toString(), SystemMessage.NOTE_BATTERY_SAVER_WARNING,
+ foregroundUser);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java
new file mode 100644
index 0000000..0af19b6
--- /dev/null
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java
@@ -0,0 +1,65 @@
+/*
+ * 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.power.batterysaver;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.util.Slog;
+
+import com.android.server.power.BatterySaverPolicy;
+import com.android.server.power.batterysaver.BatterySaverController.Plugin;
+
+public class BatterySaverLocationPlugin implements Plugin {
+ private static final String TAG = "BatterySaverLocationPlugin";
+
+ private static final boolean DEBUG = BatterySaverController.DEBUG;
+
+ private final Context mContext;
+
+ public BatterySaverLocationPlugin(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public void onBatterySaverChanged(BatterySaverController caller) {
+ if (DEBUG) {
+ Slog.d(TAG, "onBatterySaverChanged");
+ }
+ updateLocationState(caller);
+ }
+
+ @Override
+ public void onSystemReady(BatterySaverController caller) {
+ if (DEBUG) {
+ Slog.d(TAG, "onSystemReady");
+ }
+ updateLocationState(caller);
+ }
+
+ private void updateLocationState(BatterySaverController caller) {
+ final boolean kill =
+ (caller.getBatterySaverPolicy().getGpsMode()
+ == BatterySaverPolicy.GPS_MODE_ALL_DISABLED_WHEN_SCREEN_OFF) &&
+ caller.isEnabled() && !caller.isInteractive();
+
+ if (DEBUG) {
+ Slog.d(TAG, "Battery saver " + (kill ? "stopping" : "restoring") + " location.");
+ }
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Global.LOCATION_GLOBAL_KILL_SWITCH, kill ? 1 : 0);
+ }
+}
diff --git a/services/core/java/com/android/server/power/batterysaver/CpuFrequencies.java b/services/core/java/com/android/server/power/batterysaver/CpuFrequencies.java
index 1629486..f248509 100644
--- a/services/core/java/com/android/server/power/batterysaver/CpuFrequencies.java
+++ b/services/core/java/com/android/server/power/batterysaver/CpuFrequencies.java
@@ -54,6 +54,10 @@
mCoreAndFrequencies.clear();
try {
for (String pair : cpuNumberAndFrequencies.split("/")) {
+ pair = pair.trim();
+ if (pair.length() == 0) {
+ continue;
+ }
final String[] coreAndFreq = pair.split(":", 2);
if (coreAndFreq.length != 2) {
@@ -65,7 +69,7 @@
mCoreAndFrequencies.put(core, freq);
}
} catch (IllegalArgumentException e) {
- Slog.wtf(TAG, "Invalid configuration: " + cpuNumberAndFrequencies, e);
+ Slog.wtf(TAG, "Invalid configuration: '" + cpuNumberAndFrequencies + "'");
}
}
return this;
diff --git a/services/core/java/com/android/server/power/batterysaver/FileUpdater.java b/services/core/java/com/android/server/power/batterysaver/FileUpdater.java
index cc1b540..e0ab9e9 100644
--- a/services/core/java/com/android/server/power/batterysaver/FileUpdater.java
+++ b/services/core/java/com/android/server/power/batterysaver/FileUpdater.java
@@ -16,19 +16,34 @@
package com.android.server.power.batterysaver;
import android.content.Context;
+import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
+import android.os.SystemProperties;
import android.util.ArrayMap;
+import android.util.AtomicFile;
import android.util.Slog;
+import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
import com.android.server.IoThread;
import libcore.io.IoUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Map;
@@ -47,6 +62,14 @@
private static final boolean DEBUG = BatterySaverController.DEBUG;
+ /**
+ * If this system property is set to 1, it'll skip all file writes. This can be used when
+ * one needs to change max CPU frequency for benchmarking, for example.
+ */
+ private static final String PROP_SKIP_WRITE = "debug.batterysaver.no_write_files";
+
+ private static final String TAG_DEFAULT_ROOT = "defaults";
+
// Don't do disk access with this lock held.
private final Object mLock = new Object();
@@ -93,6 +116,21 @@
RETRY_INTERVAL_MS = retryIntervalMs;
}
+ public void systemReady(boolean runtimeRestarted) {
+ synchronized (mLock) {
+ if (runtimeRestarted) {
+ // If it runtime restarted, read the original values from the disk and apply.
+ if (loadDefaultValuesLocked()) {
+ Slog.d(TAG, "Default values loaded after runtime restart; writing them...");
+ restoreDefault();
+ }
+ } else {
+ // Delete it, without checking the result. (file-not-exist is not an exception.)
+ injectDefaultValuesFilename().delete();
+ }
+ }
+ }
+
/**
* Write values to files. (Note the actual writes happen ASAP but asynchronously.)
*/
@@ -241,6 +279,7 @@
}
synchronized (mLock) {
mDefaultValues.put(file, originalValue);
+ saveDefaultValuesLocked();
}
return true;
}
@@ -252,17 +291,92 @@
@VisibleForTesting
void injectWriteToFile(String file, String value) throws IOException {
+ if (injectShouldSkipWrite()) {
+ Slog.i(TAG, "Skipped writing to '" + file + "'");
+ return;
+ }
if (DEBUG) {
Slog.d(TAG, "Writing: '" + value + "' to '" + file + "'");
}
try (FileWriter out = new FileWriter(file)) {
out.write(value);
- } catch (IOException e) {
+ } catch (IOException | RuntimeException e) {
Slog.w(TAG, "Failed writing '" + value + "' to '" + file + "': " + e.getMessage());
throw e;
}
}
+ private void saveDefaultValuesLocked() {
+ final AtomicFile file = new AtomicFile(injectDefaultValuesFilename());
+
+ FileOutputStream outs = null;
+ try {
+ file.getBaseFile().getParentFile().mkdirs();
+ outs = file.startWrite();
+
+ // Write to XML
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(outs, StandardCharsets.UTF_8.name());
+ out.startDocument(null, true);
+ out.startTag(null, TAG_DEFAULT_ROOT);
+
+ XmlUtils.writeMapXml(mDefaultValues, out, null);
+
+ // Epilogue.
+ out.endTag(null, TAG_DEFAULT_ROOT);
+ out.endDocument();
+
+ // Close.
+ file.finishWrite(outs);
+ } catch (IOException | XmlPullParserException | RuntimeException e) {
+ Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
+ file.failWrite(outs);
+ }
+ }
+
+ @VisibleForTesting
+ boolean loadDefaultValuesLocked() {
+ final AtomicFile file = new AtomicFile(injectDefaultValuesFilename());
+ if (DEBUG) {
+ Slog.d(TAG, "Loading from " + file.getBaseFile());
+ }
+ Map<String, String> read = null;
+ try (FileInputStream in = file.openRead()) {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, StandardCharsets.UTF_8.name());
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ final int depth = parser.getDepth();
+ // Check the root tag
+ final String tag = parser.getName();
+ if (depth == 1) {
+ if (!TAG_DEFAULT_ROOT.equals(tag)) {
+ Slog.e(TAG, "Invalid root tag: " + tag);
+ return false;
+ }
+ continue;
+ }
+ final String[] tagName = new String[1];
+ read = (ArrayMap<String, String>) XmlUtils.readThisArrayMapXml(parser,
+ TAG_DEFAULT_ROOT, tagName, null);
+ }
+ } catch (FileNotFoundException e) {
+ read = null;
+ } catch (IOException | XmlPullParserException | RuntimeException e) {
+ Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
+ }
+ if (read != null) {
+ mDefaultValues.clear();
+ mDefaultValues.putAll(read);
+ return true;
+ }
+ return false;
+ }
+
private void doWtf(String message) {
injectWtf(message, null);
}
@@ -271,4 +385,20 @@
void injectWtf(String message, Throwable e) {
Slog.wtf(TAG, message, e);
}
+
+ File injectDefaultValuesFilename() {
+ final File dir = new File(Environment.getDataSystemDirectory(), "battery-saver");
+ dir.mkdirs();
+ return new File(dir, "default-values.xml");
+ }
+
+ @VisibleForTesting
+ boolean injectShouldSkipWrite() {
+ return SystemProperties.getBoolean(PROP_SKIP_WRITE, false);
+ }
+
+ @VisibleForTesting
+ ArrayMap<String, String> getDefaultValuesForTest() {
+ return mDefaultValues;
+ }
}
diff --git a/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java b/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
index ab9ab67..a8c68c0 100644
--- a/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
+++ b/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
@@ -63,7 +63,7 @@
PackageInfo packageInfo = mPackageManager.getPackageInfoAsUser(packageNames[i],
PackageManager.GET_SIGNATURES, userId);
keyAttestationPackageInfos[i] = new KeyAttestationPackageInfo(packageNames[i],
- packageInfo.versionCode, packageInfo.signatures);
+ packageInfo.getLongVersionCode(), packageInfo.signatures);
}
} catch (NameNotFoundException nnfe) {
throw new RemoteException(nnfe.getMessage());
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
new file mode 100644
index 0000000..047e270
--- /dev/null
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -0,0 +1,61 @@
+/*
+ * 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.slice;
+
+import android.app.slice.ISliceManager;
+import android.content.Context;
+
+import com.android.server.SystemService;
+
+public class SliceManagerService extends ISliceManager.Stub {
+
+ public SliceManagerService(Context context) {
+
+ }
+
+ private void systemReady() {
+ }
+
+ private void onUnlockUser(int userHandle) {
+ }
+
+ public static class Lifecycle extends SystemService {
+ private SliceManagerService mService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mService = new SliceManagerService(getContext());
+ publishBinderService(Context.SLICE_SERVICE, mService);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ mService.systemReady();
+ }
+ }
+
+ @Override
+ public void onUnlockUser(int userHandle) {
+ mService.onUnlockUser(userHandle);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 3772371..1ce1400 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -15,6 +15,7 @@
*/
package com.android.server.stats;
+import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -25,16 +26,22 @@
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.net.NetworkStats;
+import android.net.wifi.IWifiManager;
+import android.net.wifi.WifiActivityEnergyInfo;
+import android.telephony.ModemActivityInfo;
+import android.telephony.TelephonyManager;
import android.os.BatteryStatsInternal;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IStatsCompanionService;
import android.os.IStatsManager;
+import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StatsLogEventWrapper;
+import android.os.SynchronousResultReceiver;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
@@ -52,6 +59,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.TimeoutException;
/**
* Helper service for statsd (the native stats management service in cmds/statsd/).
@@ -60,6 +68,13 @@
* @hide
*/
public class StatsCompanionService extends IStatsCompanionService.Stub {
+ /**
+ * How long to wait on an individual subsystem to return its stats.
+ */
+ private static final long EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS = 2000;
+
+ public static final String RESULT_RECEIVER_CONTROLLER_KEY = "controller_activity";
+
static final String TAG = "StatsCompanionService";
static final boolean DEBUG = true;
public static final String ACTION_TRIGGER_COLLECTION =
@@ -79,6 +94,8 @@
private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
private final KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
+ private IWifiManager mWifiManager = null;
+ private TelephonyManager mTelephony = null;
public StatsCompanionService(Context context) {
super();
@@ -138,6 +155,14 @@
return ret;
}
+ private final static long[] toLongArray(List<Long> list) {
+ long[] ret = new long[list.size()];
+ for (int i = 0; i < ret.length; i++) {
+ ret[i] = list.get(i);
+ }
+ return ret;
+ }
+
// Assumes that sStatsdLock is held.
private final void informAllUidsLocked(Context context) throws RemoteException {
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
@@ -148,7 +173,7 @@
}
List<Integer> uids = new ArrayList();
- List<Integer> versions = new ArrayList();
+ List<Long> versions = new ArrayList();
List<String> apps = new ArrayList();
// Add in all the apps for every user/profile.
@@ -157,12 +182,12 @@
for (int j = 0; j < pi.size(); j++) {
if (pi.get(j).applicationInfo != null) {
uids.add(pi.get(j).applicationInfo.uid);
- versions.add(pi.get(j).versionCode);
+ versions.add(pi.get(j).getLongVersionCode());
apps.add(pi.get(j).packageName);
}
}
}
- sStatsd.informAllUidData(toIntArray(uids), toIntArray(versions), apps.toArray(new
+ sStatsd.informAllUidData(toIntArray(uids), toLongArray(versions), apps.toArray(new
String[apps.size()]));
if (DEBUG) {
Slog.w(TAG, "Sent data for " + uids.size() + " apps");
@@ -205,7 +230,7 @@
int uid = b.getInt(Intent.EXTRA_UID);
String app = intent.getData().getSchemeSpecificPart();
PackageInfo pi = pm.getPackageInfo(app, PackageManager.MATCH_ANY_USER);
- sStatsd.informOnePackage(app, uid, pi.versionCode);
+ sStatsd.informOnePackage(app, uid, pi.getLongVersionCode());
}
} catch (Exception e) {
Slog.w(TAG, "Failed to inform statsd of an app update", e);
@@ -389,6 +414,40 @@
return ret;
}
+ /**
+ * Helper method to extract the Parcelable controller info from a
+ * SynchronousResultReceiver.
+ */
+ private static <T extends Parcelable> T awaitControllerInfo(
+ @Nullable SynchronousResultReceiver receiver) {
+ if (receiver == null) {
+ return null;
+ }
+
+ try {
+ final SynchronousResultReceiver.Result result =
+ receiver.awaitResult(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS);
+ if (result.bundle != null) {
+ // This is the final destination for the Bundle.
+ result.bundle.setDefusable(true);
+
+ final T data = result.bundle.getParcelable(
+ RESULT_RECEIVER_CONTROLLER_KEY);
+ if (data != null) {
+ return data;
+ }
+ }
+ Slog.e(TAG, "no controller energy info supplied for " + receiver.getName());
+ } catch (TimeoutException e) {
+ Slog.w(TAG, "timeout reading " + receiver.getName() + " stats");
+ }
+ return null;
+ }
+
+ /**
+ *
+ * Pulls wifi controller activity energy info from WiFiManager
+ */
@Override // Binder call
public StatsLogEventWrapper[] pullData(int tagId) {
enforceCallingPermission();
@@ -509,6 +568,59 @@
}
return ret.toArray(new StatsLogEventWrapper[ret.size()]);
}
+ case StatsLog.WIFI_ACTIVITY_ENERGY_INFO_PULLED: {
+ List<StatsLogEventWrapper> ret = new ArrayList();
+ long token = Binder.clearCallingIdentity();
+ if (mWifiManager == null) {
+ mWifiManager = IWifiManager.Stub.asInterface(ServiceManager.getService(
+ Context.WIFI_SERVICE));
+ }
+ if (mWifiManager != null) {
+ try {
+ SynchronousResultReceiver wifiReceiver = new SynchronousResultReceiver("wifi");
+ mWifiManager.requestActivityInfo(wifiReceiver);
+ final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver);
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6);
+ e.writeLong(wifiInfo.getTimeStamp());
+ e.writeInt(wifiInfo.getStackState());
+ e.writeLong(wifiInfo.getControllerTxTimeMillis());
+ e.writeLong(wifiInfo.getControllerRxTimeMillis());
+ e.writeLong(wifiInfo.getControllerIdleTimeMillis());
+ e.writeLong(wifiInfo.getControllerEnergyUsed());
+ ret.add(e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Pulling wifiManager for wifi controller activity energy info has error", e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ break;
+ }
+ case StatsLog.MODEM_ACTIVITY_INFO_PULLED: {
+ List<StatsLogEventWrapper> ret = new ArrayList();
+ long token = Binder.clearCallingIdentity();
+ if (mTelephony == null) {
+ mTelephony = TelephonyManager.from(mContext);
+ }
+ if (mTelephony != null) {
+ SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony");
+ mTelephony.requestModemActivityInfo(modemReceiver);
+ final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver);
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6);
+ e.writeLong(modemInfo.getTimestamp());
+ e.writeLong(modemInfo.getSleepTimeMillis());
+ e.writeLong(modemInfo.getIdleTimeMillis());
+ e.writeLong(modemInfo.getTxTimeMillis()[0]);
+ e.writeLong(modemInfo.getTxTimeMillis()[1]);
+ e.writeLong(modemInfo.getTxTimeMillis()[2]);
+ e.writeLong(modemInfo.getTxTimeMillis()[3]);
+ e.writeLong(modemInfo.getTxTimeMillis()[4]);
+ e.writeLong(modemInfo.getRxTimeMillis());
+ e.writeLong(modemInfo.getEnergyUsed());
+ ret.add(e);
+ }
+ break;
+ }
default:
Slog.w(TAG, "No such tagId data as " + tagId);
return null;
@@ -523,6 +635,18 @@
sayHiToStatsd(); // tell statsd that we're ready too and link to it
}
+ @Override
+ public void triggerUidSnapshot() {
+ enforceCallingPermission();
+ synchronized (sStatsdLock) {
+ try {
+ informAllUidsLocked(mContext);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to trigger uid snapshot.", e);
+ }
+ }
+ }
+
private void enforceCallingPermission() {
if (Binder.getCallingPid() == Process.myPid()) {
return;
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index b07fe98..3792bc6 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -90,6 +90,13 @@
boolean showShutdownUi(boolean isReboot, String requestString);
+ /**
+ * Show a rotation suggestion that a user may approve to rotate the screen.
+ *
+ * @param rotation rotation suggestion
+ */
+ void onProposedRotationChanged(int rotation);
+
public interface GlobalActionsListener {
/**
* Called when sysui starts and connects its status bar, or when the status bar binder
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index c78a340..c7c03b4 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -406,6 +406,15 @@
}
return false;
}
+
+ @Override
+ public void onProposedRotationChanged(int rotation) {
+ if (mBar != null){
+ try {
+ mBar.onProposedRotationChanged(rotation);
+ } catch (RemoteException ex) {}
+ }
+ }
};
// ================================================================================
diff --git a/services/core/java/com/android/server/timezone/CheckToken.java b/services/core/java/com/android/server/timezone/CheckToken.java
index 5128360..4c4a8d7 100644
--- a/services/core/java/com/android/server/timezone/CheckToken.java
+++ b/services/core/java/com/android/server/timezone/CheckToken.java
@@ -46,8 +46,8 @@
ByteArrayOutputStream baos = new ByteArrayOutputStream(12 /* (3 * sizeof(int)) */);
try (DataOutputStream dos = new DataOutputStream(baos)) {
dos.writeInt(mOptimisticLockId);
- dos.writeInt(mPackageVersions.mUpdateAppVersion);
- dos.writeInt(mPackageVersions.mDataAppVersion);
+ dos.writeLong(mPackageVersions.mUpdateAppVersion);
+ dos.writeLong(mPackageVersions.mDataAppVersion);
} catch (IOException e) {
throw new RuntimeException("Unable to write into a ByteArrayOutputStream", e);
}
@@ -58,8 +58,8 @@
ByteArrayInputStream bais = new ByteArrayInputStream(tokenBytes);
try (DataInputStream dis = new DataInputStream(bais)) {
int versionId = dis.readInt();
- int updateAppVersion = dis.readInt();
- int dataAppVersion = dis.readInt();
+ long updateAppVersion = dis.readLong();
+ long dataAppVersion = dis.readLong();
return new CheckToken(versionId, new PackageVersions(updateAppVersion, dataAppVersion));
}
}
diff --git a/services/core/java/com/android/server/timezone/PackageManagerHelper.java b/services/core/java/com/android/server/timezone/PackageManagerHelper.java
index 804941a..f6e35e8 100644
--- a/services/core/java/com/android/server/timezone/PackageManagerHelper.java
+++ b/services/core/java/com/android/server/timezone/PackageManagerHelper.java
@@ -26,7 +26,7 @@
*/
interface PackageManagerHelper {
- int getInstalledPackageVersion(String packageName)
+ long getInstalledPackageVersion(String packageName)
throws PackageManager.NameNotFoundException;
boolean isPrivilegedApp(String packageName) throws PackageManager.NameNotFoundException;
diff --git a/services/core/java/com/android/server/timezone/PackageStatusStorage.java b/services/core/java/com/android/server/timezone/PackageStatusStorage.java
index cac7f7b..5601c91 100644
--- a/services/core/java/com/android/server/timezone/PackageStatusStorage.java
+++ b/services/core/java/com/android/server/timezone/PackageStatusStorage.java
@@ -76,7 +76,7 @@
*/
private static final String ATTRIBUTE_DATA_APP_VERSION = "dataAppPackageVersion";
- private static final int UNKNOWN_PACKAGE_VERSION = -1;
+ private static final long UNKNOWN_PACKAGE_VERSION = -1;
private final AtomicFile mPackageStatusFile;
@@ -320,14 +320,14 @@
serializer.attribute(namespace, ATTRIBUTE_CHECK_STATUS, statusAttributeValue);
serializer.attribute(namespace, ATTRIBUTE_OPTIMISTIC_LOCK_ID,
Integer.toString(optimisticLockId));
- int updateAppVersion = status == null
+ long updateAppVersion = status == null
? UNKNOWN_PACKAGE_VERSION : packageVersions.mUpdateAppVersion;
serializer.attribute(namespace, ATTRIBUTE_UPDATE_APP_VERSION,
- Integer.toString(updateAppVersion));
- int dataAppVersion = status == null
+ Long.toString(updateAppVersion));
+ long dataAppVersion = status == null
? UNKNOWN_PACKAGE_VERSION : packageVersions.mDataAppVersion;
serializer.attribute(namespace, ATTRIBUTE_DATA_APP_VERSION,
- Integer.toString(dataAppVersion));
+ Long.toString(dataAppVersion));
serializer.endTag(namespace, TAG_PACKAGE_STATUS);
serializer.endDocument();
serializer.flush();
diff --git a/services/core/java/com/android/server/timezone/PackageTracker.java b/services/core/java/com/android/server/timezone/PackageTracker.java
index f0306b9..1c54320 100644
--- a/services/core/java/com/android/server/timezone/PackageTracker.java
+++ b/services/core/java/com/android/server/timezone/PackageTracker.java
@@ -445,8 +445,8 @@
}
private PackageVersions lookupInstalledPackageVersions() {
- int updatePackageVersion;
- int dataPackageVersion;
+ long updatePackageVersion;
+ long dataPackageVersion;
try {
updatePackageVersion =
mPackageManagerHelper.getInstalledPackageVersion(mUpdateAppPackageName);
diff --git a/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java b/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java
index b89dd38..6a330e6 100644
--- a/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java
+++ b/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java
@@ -81,11 +81,11 @@
}
@Override
- public int getInstalledPackageVersion(String packageName)
+ public long getInstalledPackageVersion(String packageName)
throws PackageManager.NameNotFoundException {
int flags = PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, flags);
- return packageInfo.versionCode;
+ return packageInfo.getLongVersionCode();
}
@Override
diff --git a/services/core/java/com/android/server/timezone/PackageVersions.java b/services/core/java/com/android/server/timezone/PackageVersions.java
index fc0d6e1..0084c1a 100644
--- a/services/core/java/com/android/server/timezone/PackageVersions.java
+++ b/services/core/java/com/android/server/timezone/PackageVersions.java
@@ -21,10 +21,10 @@
*/
final class PackageVersions {
- final int mUpdateAppVersion;
- final int mDataAppVersion;
+ final long mUpdateAppVersion;
+ final long mDataAppVersion;
- PackageVersions(int updateAppVersion, int dataAppVersion) {
+ PackageVersions(long updateAppVersion, long dataAppVersion) {
this.mUpdateAppVersion = updateAppVersion;
this.mDataAppVersion = dataAppVersion;
}
@@ -48,8 +48,8 @@
@Override
public int hashCode() {
- int result = mUpdateAppVersion;
- result = 31 * result + mDataAppVersion;
+ int result = Long.hashCode(mUpdateAppVersion);
+ result = 31 * result + Long.hashCode(mDataAppVersion);
return result;
}
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 1f4e64e..7d55b68 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -59,6 +59,7 @@
import android.util.Slog;
import android.util.SparseArray;
import com.android.server.wm.WindowManagerInternal;
+import android.view.inputmethod.InputMethodManagerInternal;
import com.android.internal.R;
import com.android.internal.util.DumpUtils;
@@ -609,6 +610,14 @@
}
@Override
+ public void setVrInputMethod(ComponentName componentName) {
+ enforceCallerPermissionAnyOf(Manifest.permission.RESTRICTED_VR_ACCESS);
+ InputMethodManagerInternal imm =
+ LocalServices.getService(InputMethodManagerInternal.class);
+ imm.startVrInputMethodNoCheck(componentName);
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index 1e334b8..4aa2b37 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -156,9 +156,10 @@
return mWebViewProviderPackages;
}
- public int getFactoryPackageVersion(String packageName) throws NameNotFoundException {
+ public long getFactoryPackageVersion(String packageName) throws NameNotFoundException {
PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
- return pm.getPackageInfo(packageName, PackageManager.MATCH_FACTORY_ONLY).versionCode;
+ return pm.getPackageInfo(packageName, PackageManager.MATCH_FACTORY_ONLY)
+ .getLongVersionCode();
}
/**
diff --git a/services/core/java/com/android/server/webkit/SystemInterface.java b/services/core/java/com/android/server/webkit/SystemInterface.java
index d57edcd..405fe7d 100644
--- a/services/core/java/com/android/server/webkit/SystemInterface.java
+++ b/services/core/java/com/android/server/webkit/SystemInterface.java
@@ -36,7 +36,7 @@
public interface SystemInterface {
public WebViewProviderInfo[] getWebViewPackages();
public int onWebViewProviderChanged(PackageInfo packageInfo);
- public int getFactoryPackageVersion(String packageName) throws NameNotFoundException;
+ public long getFactoryPackageVersion(String packageName) throws NameNotFoundException;
public String getUserChosenWebViewProvider(Context context);
public void updateUserSetting(Context context, String newProviderName);
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdater.java b/services/core/java/com/android/server/webkit/WebViewUpdater.java
index 7fc907f..7e05e46 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdater.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdater.java
@@ -54,7 +54,7 @@
private Context mContext;
private SystemInterface mSystemInterface;
- private int mMinimumVersionCode = -1;
+ private long mMinimumVersionCode = -1;
// Keeps track of the number of running relro creations
private int mNumRelroCreationsStarted = 0;
@@ -430,7 +430,7 @@
if (!UserPackage.hasCorrectTargetSdkVersion(packageInfo)) {
return VALIDITY_INCORRECT_SDK_VERSION;
}
- if (!versionCodeGE(packageInfo.versionCode, getMinimumVersionCode())
+ if (!versionCodeGE(packageInfo.getLongVersionCode(), getMinimumVersionCode())
&& !mSystemInterface.systemIsDebuggable()) {
// Webview providers may be downgraded arbitrarily low, prevent that by enforcing
// minimum version code. This check is only enforced for user builds.
@@ -461,9 +461,9 @@
*
* @return true if versionCode1 is higher than or equal to versionCode2.
*/
- private static boolean versionCodeGE(int versionCode1, int versionCode2) {
- int v1 = versionCode1 / 100000;
- int v2 = versionCode2 / 100000;
+ private static boolean versionCodeGE(long versionCode1, long versionCode2) {
+ long v1 = versionCode1 / 100000;
+ long v2 = versionCode2 / 100000;
return v1 >= v2;
}
@@ -478,16 +478,16 @@
* (mMinimumVersionCode) which is shared between threads. Furthermore, this method does not
* hold mLock meaning that we must take extra care to ensure this method is thread-safe.
*/
- private int getMinimumVersionCode() {
+ private long getMinimumVersionCode() {
if (mMinimumVersionCode > 0) {
return mMinimumVersionCode;
}
- int minimumVersionCode = -1;
+ long minimumVersionCode = -1;
for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
if (provider.availableByDefault && !provider.isFallback) {
try {
- int versionCode =
+ long versionCode =
mSystemInterface.getFactoryPackageVersion(provider.packageName);
if (minimumVersionCode < 0 || versionCode < minimumVersionCode) {
minimumVersionCode = versionCode;
@@ -577,7 +577,7 @@
String packageDetails = String.format(
"versionName: %s, versionCode: %d, targetSdkVersion: %d",
systemUserPackageInfo.versionName,
- systemUserPackageInfo.versionCode,
+ systemUserPackageInfo.getLongVersionCode(),
systemUserPackageInfo.applicationInfo.targetSdkVersion);
if (validity == VALIDITY_OK) {
boolean installedForAllUsers = isInstalledAndEnabledForAllUsers(
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 3fb3773..91cad46 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -135,6 +135,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.Trace;
import android.util.DisplayMetrics;
import android.util.MutableBoolean;
import android.util.Slog;
@@ -178,20 +179,20 @@
/** The containers below are the only child containers the display can have. */
// Contains all window containers that are related to apps (Activities)
- private final TaskStackContainers mTaskStackContainers = new TaskStackContainers();
+ private final TaskStackContainers mTaskStackContainers = new TaskStackContainers(mService);
// Contains all non-app window containers that should be displayed above the app containers
// (e.g. Status bar)
- private final NonAppWindowContainers mAboveAppWindowsContainers =
- new NonAppWindowContainers("mAboveAppWindowsContainers");
+ private final AboveAppWindowContainers mAboveAppWindowsContainers =
+ new AboveAppWindowContainers("mAboveAppWindowsContainers", mService);
// Contains all non-app window containers that should be displayed below the app containers
// (e.g. Wallpaper).
private final NonAppWindowContainers mBelowAppWindowsContainers =
- new NonAppWindowContainers("mBelowAppWindowsContainers");
+ new NonAppWindowContainers("mBelowAppWindowsContainers", mService);
// Contains all IME window containers. Note that the z-ordering of the IME windows will depend
// on the IME target. We mainly have this container grouping so we can keep track of all the IME
// window containers together and move them in-sync if/when needed.
private final NonAppWindowContainers mImeWindowsContainers =
- new NonAppWindowContainers("mImeWindowsContainers");
+ new NonAppWindowContainers("mImeWindowsContainers", mService);
private WindowState mTmpWindow;
private WindowState mTmpWindow2;
@@ -317,8 +318,6 @@
/** Used for handing back size of display */
private final Rect mTmpBounds = new Rect();
- WindowManagerService mService;
-
/** Remove this display when animation on it has completed. */
private boolean mDeferredRemoval;
@@ -356,7 +355,8 @@
/**
* We organize all top-level Surfaces in to the following layers.
* mOverlayLayer contains a few Surfaces which are always on top of others
- * and omitted from Screen-Magnification ({@link WindowState#isScreenOverlay})
+ * and omitted from Screen-Magnification, for example the strict mode flash or
+ * the magnification overlay itself.
* {@link #mWindowingLayer} contains everything else.
*/
private SurfaceControl mOverlayLayer;
@@ -764,6 +764,7 @@
*/
DisplayContent(Display display, WindowManagerService service,
WallpaperController wallpaperController) {
+ super(service);
if (service.mRoot.getDisplayContent(display.getDisplayId()) != null) {
throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
+ " already exists=" + service.mRoot.getDisplayContent(display.getDisplayId())
@@ -776,7 +777,6 @@
display.getDisplayInfo(mDisplayInfo);
display.getMetrics(mDisplayMetrics);
isDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
- mService = service;
mDisplayFrames = new DisplayFrames(mDisplayId, mDisplayInfo);
initializeDisplayBaseInfo();
mDividerControllerLocked = new DockedStackDividerController(service, this);
@@ -2338,6 +2338,7 @@
/** Updates the layer assignment of windows on this display. */
void assignWindowLayers(boolean setLayoutNeeded) {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "assignWindowLayers");
assignChildLayers(getPendingTransaction());
if (setLayoutNeeded) {
setLayoutNeeded();
@@ -2348,6 +2349,7 @@
// prepareSurfaces. This allows us to synchronize Z-ordering changes with
// the hiding and showing of surfaces.
scheduleAnimation();
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
// TODO: This should probably be called any time a visual change is made to the hierarchy like
@@ -2968,227 +2970,30 @@
* Takes a snapshot of the display. In landscape mode this grabs the whole screen.
* In portrait mode, it grabs the full screenshot.
*
- * @param width the width of the target bitmap
- * @param height the height of the target bitmap
- * @param includeFullDisplay true if the screen should not be cropped before capture
- * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
* @param config of the output bitmap
* @param wallpaperOnly true if only the wallpaper layer should be included in the screenshot
- * @param includeDecor whether to include window decors, like the status or navigation bar
- * background of the window
*/
- Bitmap screenshotApplications(IBinder appToken, int width, int height,
- boolean includeFullDisplay, float frameScale, Bitmap.Config config,
- boolean wallpaperOnly, boolean includeDecor) {
- Bitmap bitmap = screenshotApplications(appToken, width, height, includeFullDisplay,
- frameScale, wallpaperOnly, includeDecor, SurfaceControl::screenshot);
- if (bitmap == null) {
- return null;
- }
-
- if (DEBUG_SCREENSHOT) {
- // TEST IF IT's ALL BLACK
- int[] buffer = new int[bitmap.getWidth() * bitmap.getHeight()];
- bitmap.getPixels(buffer, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(),
- bitmap.getHeight());
- boolean allBlack = true;
- final int firstColor = buffer[0];
- for (int i = 0; i < buffer.length; i++) {
- if (buffer[i] != firstColor) {
- allBlack = false;
- break;
- }
- }
- if (allBlack) {
- final WindowState appWin = mScreenshotApplicationState.appWin;
- final int maxLayer = mScreenshotApplicationState.maxLayer;
- final int minLayer = mScreenshotApplicationState.minLayer;
- Slog.i(TAG_WM, "Screenshot " + appWin + " was monochrome(" +
- Integer.toHexString(firstColor) + ")! mSurfaceLayer=" +
- (appWin != null ?
- appWin.mWinAnimator.mSurfaceController.getLayer() : "null") +
- " minLayer=" + minLayer + " maxLayer=" + maxLayer);
- }
- }
-
- // Create a copy of the screenshot that is immutable and backed in ashmem.
- // This greatly reduces the overhead of passing the bitmap between processes.
- Bitmap ret = bitmap.createAshmemBitmap(config);
- bitmap.recycle();
- return ret;
- }
-
- GraphicBuffer screenshotApplicationsToBuffer(IBinder appToken, int width, int height,
- boolean includeFullDisplay, float frameScale, boolean wallpaperOnly,
- boolean includeDecor) {
- return screenshotApplications(appToken, width, height, includeFullDisplay, frameScale,
- wallpaperOnly, includeDecor, SurfaceControl::screenshotToBuffer);
- }
-
- private <E> E screenshotApplications(IBinder appToken, int width, int height,
- boolean includeFullDisplay, float frameScale, boolean wallpaperOnly,
- boolean includeDecor, Screenshoter<E> screenshoter) {
- int dw = mDisplayInfo.logicalWidth;
- int dh = mDisplayInfo.logicalHeight;
- if (dw == 0 || dh == 0) {
- if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + appToken
- + ": returning null. logical widthxheight=" + dw + "x" + dh);
- return null;
- }
-
- E bitmap;
-
- mScreenshotApplicationState.reset(appToken == null && !wallpaperOnly);
- final Rect frame = new Rect();
- final Rect stackBounds = new Rect();
-
- final int aboveAppLayer = (mService.mPolicy.getWindowLayerFromTypeLw(TYPE_APPLICATION) + 1)
- * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
- final MutableBoolean mutableIncludeFullDisplay = new MutableBoolean(includeFullDisplay);
- synchronized(mService.mWindowMap) {
+ Bitmap screenshotDisplay(Bitmap.Config config, boolean wallpaperOnly) {
+ synchronized (mService.mWindowMap) {
if (!mService.mPolicy.isScreenOn()) {
- if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Attempted to take screenshot while display"
- + " was off.");
- return null;
- }
- // Figure out the part of the screen that is actually the app.
- mScreenshotApplicationState.appWin = null;
- forAllWindows(w -> {
- if (!w.mHasSurface) {
- return false;
+ if (DEBUG_SCREENSHOT) {
+ Slog.i(TAG_WM, "Attempted to take screenshot while display was off.");
}
- if (w.mLayer >= aboveAppLayer) {
- return false;
- }
- if (wallpaperOnly && !w.mIsWallpaper) {
- return false;
- }
- if (w.mIsImWindow) {
- return false;
- } else if (w.mIsWallpaper) {
- // If this is the wallpaper layer and we're only looking for the wallpaper layer
- // then the target window state is this one.
- if (wallpaperOnly) {
- mScreenshotApplicationState.appWin = w;
- }
-
- if (mScreenshotApplicationState.appWin == null) {
- // We have not ran across the target window yet, so it is probably behind
- // the wallpaper. This can happen when the keyguard is up and all windows
- // are moved behind the wallpaper. We don't want to include the wallpaper
- // layer in the screenshot as it will cover-up the layer of the target
- // window.
- return false;
- }
- // Fall through. The target window is in front of the wallpaper. For this
- // case we want to include the wallpaper layer in the screenshot because
- // the target window might have some transparent areas.
- } else if (appToken != null) {
- if (w.mAppToken == null || w.mAppToken.token != appToken) {
- // This app window is of no interest if it is not associated with the
- // screenshot app.
- return false;
- }
- mScreenshotApplicationState.appWin = w;
- }
-
- // Include this window.
-
- final WindowStateAnimator winAnim = w.mWinAnimator;
-
- // Don't include wallpaper in bounds calculation
- if (!w.mIsWallpaper && !mutableIncludeFullDisplay.value) {
- if (includeDecor) {
- final Task task = w.getTask();
- if (task != null) {
- task.getBounds(frame);
- } else {
-
- // No task bounds? Too bad! Ain't no screenshot then.
- return true;
- }
- } else {
- final Rect wf = w.mFrame;
- final Rect cr = w.mContentInsets;
- int left = wf.left + cr.left;
- int top = wf.top + cr.top;
- int right = wf.right - cr.right;
- int bottom = wf.bottom - cr.bottom;
- frame.union(left, top, right, bottom);
- w.getVisibleBounds(stackBounds);
- if (!Rect.intersects(frame, stackBounds)) {
- // Set frame empty if there's no intersection.
- frame.setEmpty();
- }
- }
- }
-
- final boolean foundTargetWs =
- (w.mAppToken != null && w.mAppToken.token == appToken)
- || (mScreenshotApplicationState.appWin != null && wallpaperOnly);
- if (foundTargetWs && winAnim.getShown() && winAnim.mLastAlpha > 0f) {
- mScreenshotApplicationState.screenshotReady = true;
- }
-
- if (w.isObscuringDisplay()){
- return true;
- }
- return false;
- }, true /* traverseTopToBottom */);
-
- final WindowState appWin = mScreenshotApplicationState.appWin;
- final boolean screenshotReady = mScreenshotApplicationState.screenshotReady;
-
- if (appToken != null && appWin == null) {
- // Can't find a window to snapshot.
- if (DEBUG_SCREENSHOT) Slog.i(TAG_WM,
- "Screenshot: Couldn't find a surface matching " + appToken);
return null;
}
- if (!screenshotReady) {
- Slog.i(TAG_WM, "Failed to capture screenshot of " + appToken +
- " appWin=" + (appWin == null ? "null" : (appWin + " drawState=" +
- appWin.mWinAnimator.mDrawState)));
+ if (wallpaperOnly && !shouldScreenshotWallpaper()) {
return null;
}
- // Screenshot is ready to be taken. Everything from here below will continue
- // through the bottom of the loop and return a value. We only stay in the loop
- // because we don't want to release the mWindowMap lock until the screenshot is
- // taken.
+ int dw = mDisplayInfo.logicalWidth;
+ int dh = mDisplayInfo.logicalHeight;
-
- if (!mutableIncludeFullDisplay.value) {
- // Constrain frame to the screen size.
- if (!frame.intersect(0, 0, dw, dh)) {
- frame.setEmpty();
- }
- } else {
- // Caller just wants entire display.
- frame.set(0, 0, dw, dh);
- }
- if (frame.isEmpty()) {
+ if (dw <= 0 || dh <= 0) {
return null;
}
- if (width < 0) {
- width = (int) (frame.width() * frameScale);
- }
- if (height < 0) {
- height = (int) (frame.height() * frameScale);
- }
-
- // Tell surface flinger what part of the image to crop. Take the top
- // right part of the application, and crop the larger dimension to fit.
- Rect crop = new Rect(frame);
- if (width / (float) frame.width() < height / (float) frame.height()) {
- int cropWidth = (int)((float)width / (float)height * frame.height());
- crop.right = crop.left + cropWidth;
- } else {
- int cropHeight = (int)((float)height / (float)width * frame.width());
- crop.bottom = crop.top + cropHeight;
- }
+ final Rect frame = new Rect(0, 0, dw, dh);
// The screenshot API does not apply the current screen rotation.
int rot = mDisplay.getRotation();
@@ -3197,43 +3002,52 @@
rot = (rot == ROTATION_90) ? ROTATION_270 : ROTATION_90;
}
- // Surfaceflinger is not aware of orientation, so convert our logical
- // crop to surfaceflinger's portrait orientation.
- convertCropForSurfaceFlinger(crop, rot, dw, dh);
-
- if (DEBUG_SCREENSHOT) {
- forAllWindows(w -> {
- final WindowSurfaceController controller = w.mWinAnimator.mSurfaceController;
- Slog.i(TAG_WM, w + ": " + w.mLayer
- + " animLayer=" + w.mWinAnimator.mAnimLayer
- + " surfaceLayer=" + ((controller == null)
- ? "null" : controller.getLayer()));
- }, false /* traverseTopToBottom */);
- }
+ // SurfaceFlinger is not aware of orientation, so convert our logical
+ // crop to SurfaceFlinger's portrait orientation.
+ convertCropForSurfaceFlinger(frame, rot, dw, dh);
final ScreenRotationAnimation screenRotationAnimation =
mService.mAnimator.getScreenRotationAnimationLocked(DEFAULT_DISPLAY);
final boolean inRotation = screenRotationAnimation != null &&
screenRotationAnimation.isAnimating();
- if (DEBUG_SCREENSHOT && inRotation) Slog.v(TAG_WM,
- "Taking screenshot while rotating");
-
- // We force pending transactions to flush before taking
- // the screenshot by pushing an empty synchronous transaction.
- SurfaceControl.openTransaction();
- SurfaceControl.closeTransactionSync();
+ if (DEBUG_SCREENSHOT && inRotation) Slog.v(TAG_WM, "Taking screenshot while rotating");
// TODO(b/68392460): We should screenshot Task controls directly
// but it's difficult at the moment as the Task doesn't have the
// correct size set.
- bitmap = screenshoter.screenshot(crop, width, height, 0, 1,
- inRotation, rot);
+ final Bitmap bitmap = SurfaceControl.screenshot(frame, dw, dh, 0, 1, inRotation, rot);
if (bitmap == null) {
Slog.w(TAG_WM, "Failed to take screenshot");
return null;
}
+
+ // Create a copy of the screenshot that is immutable and backed in ashmem.
+ // This greatly reduces the overhead of passing the bitmap between processes.
+ final Bitmap ret = bitmap.createAshmemBitmap(config);
+ bitmap.recycle();
+ return ret;
}
- return bitmap;
+ }
+
+ private boolean shouldScreenshotWallpaper() {
+ MutableBoolean screenshotReady = new MutableBoolean(false);
+
+ forAllWindows(w -> {
+ if (!w.mIsWallpaper) {
+ return false;
+ }
+
+ // Found the wallpaper window
+ final WindowStateAnimator winAnim = w.mWinAnimator;
+
+ if (winAnim.getShown() && winAnim.mLastAlpha > 0f) {
+ screenshotReady.value = true;
+ }
+
+ return true;
+ }, true /* traverseTopToBottom */);
+
+ return screenshotReady.value;
}
// TODO: Can this use createRotationMatrix()?
@@ -3369,6 +3183,10 @@
*/
static class DisplayChildWindowContainer<E extends WindowContainer> extends WindowContainer<E> {
+ DisplayChildWindowContainer(WindowManagerService service) {
+ super(service);
+ }
+
@Override
boolean fillsParent() {
return true;
@@ -3396,6 +3214,10 @@
private TaskStack mPinnedStack = null;
private TaskStack mSplitScreenPrimaryStack = null;
+ TaskStackContainers(WindowManagerService service) {
+ super(service);
+ }
+
/**
* Returns the topmost stack on the display that is compatible with the input windowing mode
* and activity type. Null is no compatible stack on the display.
@@ -3703,35 +3525,37 @@
@Override
void assignChildLayers(SurfaceControl.Transaction t) {
- final int NORMAL_STACK_STATE = 0;
- final int BOOSTED_STATE = 1;
- final int ALWAYS_ON_TOP_STATE = 2;
+ int layer = 0;
// We allow stacks to change visual order from the AM specified order due to
// Z-boosting during animations. However we must take care to ensure TaskStacks
// which are marked as alwaysOnTop remain that way.
- int layer = 0;
- for (int state = 0; state <= ALWAYS_ON_TOP_STATE; state++) {
- for (int i = 0; i < mChildren.size(); i++) {
- final TaskStack s = mChildren.get(i);
- layer++;
- if (state == NORMAL_STACK_STATE) {
- s.assignLayer(t, layer);
- } else if (state == BOOSTED_STATE && s.needsZBoost()) {
- s.assignLayer(t, layer);
- } else if (state == ALWAYS_ON_TOP_STATE &&
- s.isAlwaysOnTop()) {
- s.assignLayer(t, layer);
- }
- s.assignChildLayers(t);
+ for (int i = 0; i < mChildren.size(); i++) {
+ final TaskStack s = mChildren.get(i);
+ s.assignChildLayers();
+ if (!s.needsZBoost() && !s.isAlwaysOnTop()) {
+ s.assignLayer(t, layer++);
}
- // The appropriate place for App-Transitions to occur is right
- // above all other animations but still below things in the Picture-and-Picture
- // windowing mode.
- if (state == BOOSTED_STATE && mAnimationLayer != null) {
- t.setLayer(mAnimationLayer, layer + 1);
+ }
+ for (int i = 0; i < mChildren.size(); i++) {
+ final TaskStack s = mChildren.get(i);
+ if (s.needsZBoost() && !s.isAlwaysOnTop()) {
+ s.assignLayer(t, layer++);
}
}
+ for (int i = 0; i < mChildren.size(); i++) {
+ final TaskStack s = mChildren.get(i);
+ if (s.isAlwaysOnTop()) {
+ s.assignLayer(t, layer++);
+ }
+ }
+
+ // The appropriate place for App-Transitions to occur is right
+ // above all other animations but still below things in the Picture-and-Picture
+ // windowing mode.
+ if (mAnimationLayer != null) {
+ t.setLayer(mAnimationLayer, layer++);
+ }
}
@Override
@@ -3746,11 +3570,39 @@
}
}
+ private final class AboveAppWindowContainers extends NonAppWindowContainers {
+ AboveAppWindowContainers(String name, WindowManagerService service) {
+ super(name, service);
+ }
+
+ void assignChildLayers(SurfaceControl.Transaction t, WindowContainer imeContainer) {
+ boolean needAssignIme = imeContainer != null
+ && imeContainer.getSurfaceControl() != null;
+ for (int j = 0; j < mChildren.size(); ++j) {
+ final WindowToken wt = mChildren.get(j);
+ wt.assignLayer(t, j);
+ wt.assignChildLayers(t);
+
+ int layer = mService.mPolicy.getWindowLayerFromTypeLw(
+ wt.windowType, wt.mOwnerCanManageAppTokens);
+
+ if (needAssignIme && layer >= mService.mPolicy.getWindowLayerFromTypeLw(
+ TYPE_INPUT_METHOD_DIALOG, true)) {
+ imeContainer.assignRelativeLayer(t, wt.getSurfaceControl(), -1);
+ needAssignIme = false;
+ }
+ }
+ if (needAssignIme) {
+ imeContainer.assignRelativeLayer(t, getSurfaceControl(), Integer.MAX_VALUE);
+ }
+ }
+ }
+
/**
* Window container class that contains all containers on this display that are not related to
* Apps. E.g. status bar.
*/
- private final class NonAppWindowContainers extends DisplayChildWindowContainer<WindowToken> {
+ private class NonAppWindowContainers extends DisplayChildWindowContainer<WindowToken> {
/**
* Compares two child window tokens returns -1 if the first is lesser than the second in
* terms of z-order and 1 otherwise.
@@ -3775,7 +3627,8 @@
};
private final String mName;
- NonAppWindowContainers(String name) {
+ NonAppWindowContainers(String name, WindowManagerService service) {
+ super(service);
mName = name;
}
@@ -3819,15 +3672,6 @@
}
}
- /**
- * Interface to screenshot into various types, i.e. {@link Bitmap} and {@link GraphicBuffer}.
- */
- @FunctionalInterface
- private interface Screenshoter<E> {
- E screenshot(Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
- boolean useIdentityTransform, int rotation);
- }
-
SurfaceControl.Builder makeSurface(SurfaceSession s) {
return mService.makeSurfaceBuilder(s)
.setParent(mWindowingLayer);
@@ -3848,12 +3692,8 @@
return b;
}
- b.setName(child.getName());
- if (child.isScreenOverlay()) {
- return b.setParent(mOverlayLayer);
- } else {
- return b.setParent(mWindowingLayer);
- }
+ return b.setName(child.getName())
+ .setParent(mWindowingLayer);
}
/**
@@ -3882,8 +3722,6 @@
@Override
void assignChildLayers(SurfaceControl.Transaction t) {
- t.setLayer(mOverlayLayer, 1)
- .setLayer(mWindowingLayer, 0);
// These are layers as children of "mWindowingLayer"
mBelowAppWindowsContainers.assignLayer(t, 0);
@@ -3891,26 +3729,35 @@
mAboveAppWindowsContainers.assignLayer(t, 2);
WindowState imeTarget = mService.mInputMethodTarget;
- if (imeTarget == null || imeTarget.inSplitScreenWindowingMode()) {
- // In split-screen windowing mode we can't layer the
- // IME relative to the IME target because it needs to
- // go over the docked divider, so instead we place it on top
- // of everything and use relative layering of windows which need
- // to go above it (see special logic in WindowState#assignLayer)
- mImeWindowsContainers.assignLayer(t, 3);
- } else {
- t.setRelativeLayer(mImeWindowsContainers.getSurfaceControl(),
- imeTarget.getSurfaceControl(),
+ boolean needAssignIme = true;
+
+ // In the case where we have an IME target that is not in split-screen
+ // mode IME assignment is easy. We just need the IME to go directly above
+ // the target. This way children of the target will naturally go above the IME
+ // and everyone is happy.
+ //
+ // In the case of split-screen windowing mode, we need to elevate the IME above the
+ // docked divider while keeping the app itself below the docked divider, so instead
+ // we use relative layering of the IME targets child windows, and place the
+ // IME in the non-app layer (see {@link AboveAppWindowContainers#assignChildLayers}).
+ //
+ // In the case where we have no IME target we assign it where it's base layer would
+ // place it in the AboveAppWindowContainers.
+ if (imeTarget != null && !imeTarget.inSplitScreenWindowingMode()
+ && (imeTarget.getSurfaceControl() != null)) {
+ mImeWindowsContainers.assignRelativeLayer(t, imeTarget.getSurfaceControl(),
// TODO: We need to use an extra level on the app surface to ensure
// this is always above SurfaceView but always below attached window.
1);
+ needAssignIme = false;
}
// Above we have assigned layers to our children, now we ask them to assign
// layers to their children.
mBelowAppWindowsContainers.assignChildLayers(t);
mTaskStackContainers.assignChildLayers(t);
- mAboveAppWindowsContainers.assignChildLayers(t);
+ mAboveAppWindowsContainers.assignChildLayers(t,
+ needAssignIme == true ? mImeWindowsContainers : null);
mImeWindowsContainers.assignChildLayers(t);
}
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index 0249713..0155712 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -21,11 +21,17 @@
import static android.view.Surface.ROTATION_90;
import static com.android.server.wm.proto.DisplayFramesProto.STABLE_BOUNDS;
+import android.annotation.NonNull;
+import android.graphics.Point;
import android.graphics.Rect;
import android.util.proto.ProtoOutputStream;
+import android.view.DisplayCutout;
import android.view.DisplayInfo;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.PrintWriter;
+import java.util.Arrays;
/**
* Container class for all the display frames that affect how we do window layout on a display.
@@ -94,6 +100,14 @@
/** During layout, the current screen borders along which input method windows are placed. */
public final Rect mDock = new Rect();
+ /** Definition of the cutout */
+ @NonNull public DisplayCutout mDisplayCutout = DisplayCutout.NO_CUTOUT;
+
+ /**
+ * During layout, the frame that is display-cutout safe, i.e. that does not intersect with it.
+ */
+ public final Rect mDisplayCutoutSafe = new Rect();
+
private final Rect mDisplayInfoOverscan = new Rect();
private final Rect mRotatedDisplayInfoOverscan = new Rect();
public int mDisplayWidth;
@@ -114,7 +128,7 @@
info.overscanLeft, info.overscanTop, info.overscanRight, info.overscanBottom);
}
- public void onBeginLayout() {
+ public void onBeginLayout(boolean emulateDisplayCutout, int statusBarHeight) {
switch (mRotation) {
case ROTATION_90:
mRotatedDisplayInfoOverscan.left = mDisplayInfoOverscan.top;
@@ -152,13 +166,67 @@
mStable.set(mUnrestricted);
mStableFullscreen.set(mUnrestricted);
mCurrent.set(mUnrestricted);
-
+ mDisplayCutout = DisplayCutout.NO_CUTOUT;
+ mDisplayCutoutSafe.set(Integer.MIN_VALUE, Integer.MIN_VALUE,
+ Integer.MAX_VALUE, Integer.MAX_VALUE);
+ if (emulateDisplayCutout) {
+ setEmulatedDisplayCutout((int) (statusBarHeight * 0.8));
+ }
}
public int getInputMethodWindowVisibleHeight() {
return mDock.bottom - mCurrent.bottom;
}
+ private void setEmulatedDisplayCutout(int height) {
+ final boolean swappedDimensions = mRotation == ROTATION_90 || mRotation == ROTATION_270;
+
+ final int screenWidth = swappedDimensions ? mDisplayHeight : mDisplayWidth;
+ final int screenHeight = swappedDimensions ? mDisplayWidth : mDisplayHeight;
+
+ final int widthTop = (int) (screenWidth * 0.3);
+ final int widthBottom = widthTop - height;
+
+ switch (mRotation) {
+ case ROTATION_90:
+ mDisplayCutout = DisplayCutout.fromBoundingPolygon(Arrays.asList(
+ new Point(0, (screenWidth - widthTop) / 2),
+ new Point(height, (screenWidth - widthBottom) / 2),
+ new Point(height, (screenWidth + widthBottom) / 2),
+ new Point(0, (screenWidth + widthTop) / 2)
+ )).calculateRelativeTo(mUnrestricted);
+ mDisplayCutoutSafe.left = height;
+ break;
+ case ROTATION_180:
+ mDisplayCutout = DisplayCutout.fromBoundingPolygon(Arrays.asList(
+ new Point((screenWidth - widthTop) / 2, screenHeight),
+ new Point((screenWidth - widthBottom) / 2, screenHeight - height),
+ new Point((screenWidth + widthBottom) / 2, screenHeight - height),
+ new Point((screenWidth + widthTop) / 2, screenHeight)
+ )).calculateRelativeTo(mUnrestricted);
+ mDisplayCutoutSafe.bottom = screenHeight - height;
+ break;
+ case ROTATION_270:
+ mDisplayCutout = DisplayCutout.fromBoundingPolygon(Arrays.asList(
+ new Point(screenHeight, (screenWidth - widthTop) / 2),
+ new Point(screenHeight - height, (screenWidth - widthBottom) / 2),
+ new Point(screenHeight - height, (screenWidth + widthBottom) / 2),
+ new Point(screenHeight, (screenWidth + widthTop) / 2)
+ )).calculateRelativeTo(mUnrestricted);
+ mDisplayCutoutSafe.right = screenHeight - height;
+ break;
+ default:
+ mDisplayCutout = DisplayCutout.fromBoundingPolygon(Arrays.asList(
+ new Point((screenWidth - widthTop) / 2, 0),
+ new Point((screenWidth - widthBottom) / 2, height),
+ new Point((screenWidth + widthBottom) / 2, height),
+ new Point((screenWidth + widthTop) / 2, 0)
+ )).calculateRelativeTo(mUnrestricted);
+ mDisplayCutoutSafe.top = height;
+ break;
+ }
+ }
+
public void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
mStable.writeToProto(proto, STABLE_BOUNDS);
@@ -182,6 +250,7 @@
dumpFrame(mUnrestricted, "mUnrestricted", myPrefix, pw);
dumpFrame(mDisplayInfoOverscan, "mDisplayInfoOverscan", myPrefix, pw);
dumpFrame(mRotatedDisplayInfoOverscan, "mRotatedDisplayInfoOverscan", myPrefix, pw);
+ pw.println(myPrefix + "mDisplayCutout=" + mDisplayCutout);
}
private void dumpFrame(Rect frame, String name, String prefix, PrintWriter pw) {
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index e81d366..112e62f 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -645,15 +645,15 @@
try (final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()) {
transaction.setPosition(
mSurfaceControl,
- (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_X),
- (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_Y));
+ (float) animation.getAnimatedValue(ANIMATED_PROPERTY_X),
+ (float) animation.getAnimatedValue(ANIMATED_PROPERTY_Y));
transaction.setAlpha(
mSurfaceControl,
- (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_ALPHA));
+ (float) animation.getAnimatedValue(ANIMATED_PROPERTY_ALPHA));
transaction.setMatrix(
mSurfaceControl,
- (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_SCALE), 0,
- 0, (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_SCALE));
+ (float) animation.getAnimatedValue(ANIMATED_PROPERTY_SCALE), 0,
+ 0, (float) animation.getAnimatedValue(ANIMATED_PROPERTY_SCALE));
transaction.apply();
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 4008811..b08eb18 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -101,8 +101,6 @@
private static final int SET_SCREEN_BRIGHTNESS_OVERRIDE = 1;
private static final int SET_USER_ACTIVITY_TIMEOUT = 2;
- WindowManagerService mService;
-
private boolean mWallpaperForceHidingChanged = false;
private Object mLastWindowFreezeSource = null;
private Session mHoldScreen = null;
@@ -160,7 +158,7 @@
};
RootWindowContainer(WindowManagerService service) {
- mService = service;
+ super(service);
mHandler = new MyHandler(service.mH.getLooper());
mWallpaperController = new WallpaperController(mService);
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index ad7c300..63eea10 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -23,9 +23,8 @@
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
+
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -45,13 +44,13 @@
import android.util.MergedConfiguration;
import android.util.Slog;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.IWindow;
import android.view.IWindowId;
import android.view.IWindowSession;
import android.view.IWindowSessionCallback;
import android.view.InputChannel;
import android.view.Surface;
-import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.WindowManager;
@@ -192,15 +191,17 @@
int viewVisibility, Rect outContentInsets, Rect outStableInsets,
InputChannel outInputChannel) {
return addToDisplay(window, seq, attrs, viewVisibility, Display.DEFAULT_DISPLAY,
- outContentInsets, outStableInsets, null /* outOutsets */, outInputChannel);
+ outContentInsets, outStableInsets, null /* outOutsets */, null /* cutout */,
+ outInputChannel);
}
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
- Rect outOutsets, InputChannel outInputChannel) {
+ Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout,
+ InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
- outContentInsets, outStableInsets, outOutsets, outInputChannel);
+ outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);
}
@Override
@@ -214,7 +215,7 @@
public int addToDisplayWithoutInputChannel(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
- outContentInsets, outStableInsets, null /* outOutsets */, null);
+ outContentInsets, outStableInsets, null /* outOutsets */, null /* cutout */, null);
}
@Override
@@ -232,6 +233,7 @@
int requestedWidth, int requestedHeight, int viewFlags,
int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
+ DisplayCutout.ParcelableWrapper cutout,
MergedConfiguration mergedConfiguration, Surface outSurface) {
if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
+ Binder.getCallingPid());
@@ -239,7 +241,8 @@
int res = mService.relayoutWindow(this, window, seq, attrs,
requestedWidth, requestedHeight, viewFlags, flags,
outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
- outStableInsets, outsets, outBackdropFrame, mergedConfiguration, outSurface);
+ outStableInsets, outsets, outBackdropFrame, cutout,
+ mergedConfiguration, outSurface);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
+ Binder.getCallingPid());
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
index c2a4be5..e7547bf 100644
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ b/services/core/java/com/android/server/wm/StackWindowController.java
@@ -87,12 +87,6 @@
}
}
- public boolean isVisible() {
- synchronized (mWindowMap) {
- return mContainer != null && mContainer.isVisible();
- }
- }
-
public void reparent(int displayId, Rect outStackBounds, boolean onTop) {
synchronized (mWindowMap) {
if (mContainer == null) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 8aa129a..6ea8a47 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -59,7 +59,6 @@
final int mTaskId;
final int mUserId;
private boolean mDeferRemoval = false;
- final WindowManagerService mService;
final Rect mPreparedFrozenBounds = new Rect();
final Configuration mPreparedFrozenMergedConfig = new Configuration();
@@ -102,10 +101,10 @@
Task(int taskId, TaskStack stack, int userId, WindowManagerService service, int resizeMode,
boolean supportsPictureInPicture, TaskDescription taskDescription,
TaskWindowContainerController controller) {
+ super(service);
mTaskId = taskId;
mStack = stack;
mUserId = userId;
- mService = service;
mResizeMode = resizeMode;
mSupportsPictureInPicture = supportsPictureInPicture;
setController(controller);
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 5d4ba09..87d0a40 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -382,6 +382,27 @@
mStartOrientationWasLandscape = startBounds.width() >= startBounds.height();
mWindowOriginalBounds.set(startBounds);
+ // Notify the app that resizing has started, even though we haven't received any new
+ // bounds yet. This will guarantee that the app starts the backdrop renderer before
+ // configuration changes which could cause an activity restart.
+ if (mResizing) {
+ synchronized (mService.mWindowMap) {
+ notifyMoveLocked(startX, startY);
+ }
+
+ // Perform the resize on the WMS handler thread when we don't have the WMS lock held
+ // to ensure that we don't deadlock WMS and AMS. Note that WindowPositionerEventReceiver
+ // callbacks are delivered on the same handler so this initial resize is always
+ // guaranteed to happen before subsequent drag resizes.
+ mService.mH.post(() -> {
+ try {
+ mService.mActivityManager.resizeTask(
+ mTask.mTaskId, startBounds, RESIZE_MODE_USER_FORCED);
+ } catch (RemoteException e) {
+ }
+ });
+ }
+
// Make sure we always have valid drag bounds even if the drag ends before any move events
// have been handled.
mWindowDragBounds.set(startBounds);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index e644417..c091157 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -18,12 +18,12 @@
import static com.android.server.wm.TaskSnapshotPersister.DISABLE_FULL_SIZED_BITMAPS;
import static com.android.server.wm.TaskSnapshotPersister.REDUCED_SCALE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.ActivityManager.StackId;
import android.app.ActivityManager.TaskSnapshot;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
@@ -35,6 +35,7 @@
import android.util.Slog;
import android.view.DisplayListCanvas;
import android.view.RenderNode;
+import android.view.SurfaceControl;
import android.view.ThreadedRenderer;
import android.view.WindowManager.LayoutParams;
@@ -210,15 +211,32 @@
if (mainWindow == null) {
return null;
}
+ if (!mService.mPolicy.isScreenOn()) {
+ if (DEBUG_SCREENSHOT) {
+ Slog.i(TAG_WM, "Attempted to take screenshot while display was off.");
+ }
+ return null;
+ }
+ if (task.getSurfaceControl() == null) {
+ return null;
+ }
+
final boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
final float scaleFraction = isLowRamDevice ? REDUCED_SCALE : 1f;
- final GraphicBuffer buffer = top.mDisplayContent.screenshotApplicationsToBuffer(top.token,
- -1, -1, false, scaleFraction, false, true);
+ final Rect taskFrame = new Rect();
+ task.getBounds(taskFrame);
+
+ final GraphicBuffer buffer = SurfaceControl.captureLayers(
+ task.getSurfaceControl().getHandle(), taskFrame, scaleFraction);
+
if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
+ if (DEBUG_SCREENSHOT) {
+ Slog.w(TAG_WM, "Failed to take screenshot");
+ }
return null;
}
return new TaskSnapshot(buffer, top.getConfiguration().orientation,
- minRect(mainWindow.mContentInsets, mainWindow.mStableInsets),
+ getInsetsFromTaskBounds(mainWindow, task),
isLowRamDevice /* reduced */, scaleFraction /* scale */);
}
@@ -226,11 +244,18 @@
return mIsRunningOnWear || mIsRunningOnTv || mIsRunningOnIoT;
}
- private Rect minRect(Rect rect1, Rect rect2) {
- return new Rect(Math.min(rect1.left, rect2.left),
- Math.min(rect1.top, rect2.top),
- Math.min(rect1.right, rect2.right),
- Math.min(rect1.bottom, rect2.bottom));
+ private Rect getInsetsFromTaskBounds(WindowState state, Task task) {
+ final Rect r = new Rect();
+ r.set(state.getContentFrameLw());
+ r.intersectUnchecked(state.getStableFrameLw());
+
+ final Rect taskBounds = task.getBounds();
+
+ r.set(Math.max(0, r.left - taskBounds.left),
+ Math.max(0, r.top - taskBounds.top),
+ Math.max(0, taskBounds.right - r.right),
+ Math.max(0, taskBounds.bottom - r.bottom));
+ return r;
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 41915a3..259f8df 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -57,6 +57,7 @@
import android.os.SystemClock;
import android.util.MergedConfiguration;
import android.util.Slog;
+import android.view.DisplayCutout;
import android.view.IWindowSession;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -134,6 +135,7 @@
window.setSession(session);
final Surface surface = new Surface();
final Rect tmpRect = new Rect();
+ final DisplayCutout.ParcelableWrapper tmpCutout = new DisplayCutout.ParcelableWrapper();
final Rect tmpFrame = new Rect();
final Rect taskBounds;
final Rect tmpContentInsets = new Rect();
@@ -195,8 +197,8 @@
}
try {
final int res = session.addToDisplay(window, window.mSeq, layoutParams,
- View.VISIBLE, token.getDisplayContent().getDisplayId(), tmpRect, tmpRect,
- tmpRect, null);
+ View.GONE, token.getDisplayContent().getDisplayId(), tmpRect, tmpRect,
+ tmpRect, tmpCutout, null);
if (res < 0) {
Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
return null;
@@ -212,7 +214,7 @@
try {
session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame,
tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect,
- tmpMergedConfiguration, surface);
+ tmpCutout, tmpMergedConfiguration, surface);
} catch (RemoteException e) {
// Local call.
}
@@ -349,8 +351,9 @@
// Let's remove all system decorations except the status bar, but only if the task is at the
// very top of the screen.
+ final boolean isTop = mTaskBounds.top == 0 && mFrame.top == 0;
rect.inset((int) (insets.left * mSnapshot.getScale()),
- mTaskBounds.top != 0 ? (int) (insets.top * mSnapshot.getScale()) : 0,
+ isTop ? 0 : (int) (insets.top * mSnapshot.getScale()),
(int) (insets.right * mSnapshot.getScale()),
(int) (insets.bottom * mSnapshot.getScale()));
return rect;
@@ -437,7 +440,8 @@
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
Rect stableInsets, Rect outsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
- boolean alwaysConsumeNavBar, int displayId) {
+ boolean alwaysConsumeNavBar, int displayId,
+ DisplayCutout.ParcelableWrapper displayCutout) {
if (mergedConfiguration != null && mOuter != null
&& mOuter.mOrientationOnCreation
!= mergedConfiguration.getMergedConfiguration().orientation) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 4a3a3fc..832d395 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -75,9 +75,6 @@
/** Unique identifier */
final int mStackId;
- /** The service */
- private final WindowManagerService mService;
-
/** The display this stack sits under. */
// TODO: Track parent marks like this in WindowContainer.
private DisplayContent mDisplayContent;
@@ -151,7 +148,7 @@
final Rect mTmpDimBoundsRect = new Rect();
TaskStack(WindowManagerService service, int stackId, StackWindowController controller) {
- mService = service;
+ super(service);
mStackId = stackId;
setController(controller);
mDockedStackMinimizeThickness = service.mContext.getResources().getDimensionPixelSize(
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/services/core/java/com/android/server/wm/TransactionFactory.java
similarity index 63%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to services/core/java/com/android/server/wm/TransactionFactory.java
index 4ccdea5..067f083 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/services/core/java/com/android/server/wm/TransactionFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -11,14 +11,17 @@
* 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.internal.telephony;
+package com.android.server.wm;
-import android.telephony.SubscriptionInfo;
+import android.view.SurfaceControl.Transaction;
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
-}
+/**
+ * Helper class to inject custom transaction objects into window manager.
+ */
+interface TransactionFactory {
+ Transaction make();
+};
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 610453e..d6329bf 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -21,6 +21,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static com.android.server.wm.proto.WindowContainerProto.CONFIGURATION_CONTAINER;
import static com.android.server.wm.proto.WindowContainerProto.ORIENTATION;
+import static com.android.server.wm.proto.WindowContainerProto.VISIBLE;
import static android.view.SurfaceControl.Transaction;
import android.annotation.CallSuper;
@@ -71,18 +72,25 @@
WindowContainerController mController;
protected SurfaceControl mSurfaceControl;
+ private int mLastLayer = 0;
+ private SurfaceControl mLastRelativeToLayer = null;
/**
* Applied as part of the animation pass in "prepareSurfaces".
*/
- private Transaction mPendingTransaction = new Transaction();
+ private final Transaction mPendingTransaction;
+ protected final WindowManagerService mService;
+
+ WindowContainer(WindowManagerService service) {
+ mService = service;
+ mPendingTransaction = service.mTransactionFactory.make();
+ }
@Override
final protected WindowContainer getParent() {
return mParent;
}
-
@Override
protected int getChildCount() {
return mChildren.size();
@@ -731,29 +739,8 @@
final WindowContainer p = getParent();
// Give the parent a chance to set properties. In hierarchy v1 we rely
// on this to set full-screen dimensions on all our Surface-less Layers.
- final SurfaceControl.Builder b = p.makeChildSurface(child);
- if (child != null && child.isScreenOverlay()) {
- // If it's a screen overlay it's been promoted in the hierarchy (wrt to the
- // WindowContainer hierarchy vs the SurfaceControl hierarchy)
- // and we shouldn't set ourselves as the parent.
- return b;
- } else {
- return b.setParent(mSurfaceControl);
- }
- }
-
- /**
- * There are various layers which require promotion from the WindowContainer
- * hierarchy to the Overlay layer described in {@link DisplayContent}. See {@link WindowState}
- * for the particular usage.
- *
- * TODO: Perhaps this should be eliminated, either through modifying
- * the window container hierarchy or through modifying the way we express these overlay
- * Surfaces (for example, the Magnification Overlay could be implemented like the Strict-mode
- * Flash and not actually use a WindowState).
- */
- boolean isScreenOverlay() {
- return false;
+ return p.makeChildSurface(child)
+ .setParent(mSurfaceControl);
}
/**
@@ -776,34 +763,46 @@
}
void assignLayer(Transaction t, int layer) {
- if (mSurfaceControl != null) {
+ final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
+ if (mSurfaceControl != null && changed) {
t.setLayer(mSurfaceControl, layer);
+ mLastLayer = layer;
+ mLastRelativeToLayer = null;
+ }
+ }
+
+ void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
+ final boolean changed = layer != mLastLayer || mLastRelativeToLayer != relativeTo;
+ if (mSurfaceControl != null && changed) {
+ t.setRelativeLayer(mSurfaceControl, relativeTo, layer);
+ mLastLayer = layer;
+ mLastRelativeToLayer = relativeTo;
}
}
void assignChildLayers(Transaction t) {
int layer = 0;
- boolean boosting = false;
// We use two passes as a way to promote children which
// need Z-boosting to the end of the list.
- for (int i = 0; i < 2; i++ ) {
- for (int j = 0; j < mChildren.size(); ++j) {
- final WindowContainer wc = mChildren.get(j);
- if (wc.needsZBoost() && !boosting) {
- continue;
- }
- wc.assignLayer(t, layer);
- wc.assignChildLayers(t);
-
- layer++;
+ for (int j = 0; j < mChildren.size(); ++j) {
+ final WindowContainer wc = mChildren.get(j);
+ wc.assignChildLayers(t);
+ if (!wc.needsZBoost()) {
+ wc.assignLayer(t, layer++);
}
- boosting = true;
+ }
+ for (int j = 0; j < mChildren.size(); ++j) {
+ final WindowContainer wc = mChildren.get(j);
+ if (wc.needsZBoost()) {
+ wc.assignLayer(t, layer++);
+ }
}
}
void assignChildLayers() {
assignChildLayers(getPendingTransaction());
+ scheduleAnimation();
}
boolean needsZBoost() {
@@ -830,6 +829,7 @@
final long token = proto.start(fieldId);
super.writeToProto(proto, CONFIGURATION_CONTAINER, trim);
proto.write(ORIENTATION, mOrientation);
+ proto.write(VISIBLE, isVisible());
proto.end(token);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1cd4080..e598224 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -65,6 +65,8 @@
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
+
+import static com.android.internal.util.LatencyTracker.ACTION_ROTATE_SCREEN;
import static com.android.server.LockGuard.INDEX_WINDOW;
import static com.android.server.LockGuard.installLock;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
@@ -189,6 +191,7 @@
import android.util.proto.ProtoOutputStream;
import android.view.AppTransitionAnimationSpec;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IAppTransitionAnimationSpecsFuture;
@@ -212,6 +215,7 @@
import android.view.PointerIcon;
import android.view.Surface;
import android.view.SurfaceControl;
+import android.view.SurfaceControl.Builder;
import android.view.SurfaceSession;
import android.view.View;
import android.view.WindowContentFrameStats;
@@ -229,6 +233,7 @@
import com.android.internal.policy.IShortcutService;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.LatencyTracker;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
import com.android.internal.view.IInputMethodManager;
@@ -771,6 +776,8 @@
private WindowContentFrameStats mTempWindowRenderStats;
+ private final LatencyTracker mLatencyTracker;
+
/**
* Whether the UI is currently running in touch mode (not showing
* navigational focus because the user is directly pressing the screen).
@@ -800,12 +807,8 @@
static WindowManagerThreadPriorityBooster sThreadPriorityBooster =
new WindowManagerThreadPriorityBooster();
- class DefaultSurfaceBuilderFactory implements SurfaceBuilderFactory {
- public SurfaceControl.Builder make(SurfaceSession s) {
- return new SurfaceControl.Builder(s);
- }
- };
- SurfaceBuilderFactory mSurfaceBuilderFactory = new DefaultSurfaceBuilderFactory();
+ SurfaceBuilderFactory mSurfaceBuilderFactory = SurfaceControl.Builder::new;
+ TransactionFactory mTransactionFactory = SurfaceControl.Transaction::new;
static void boostPriorityForLockedSection() {
sThreadPriorityBooster.boost();
@@ -1070,6 +1073,8 @@
filter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiver(mBroadcastReceiver, filter);
+ mLatencyTracker = LatencyTracker.getInstance(context);
+
mSettingsObserver = new SettingsObserver();
mHoldingScreenWakeLock = mPowerManager.newWakeLock(
@@ -1129,9 +1134,9 @@
}
public int addWindow(Session session, IWindow client, int seq,
- WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
+ LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
- InputChannel outInputChannel) {
+ DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
int[] appOp = new int[1];
int res = mPolicy.checkAddPermission(attrs, appOp);
if (res != WindowManagerGlobal.ADD_OKAY) {
@@ -1466,7 +1471,7 @@
taskBounds = null;
}
if (mPolicy.getInsetHintLw(win.mAttrs, taskBounds, displayFrames, outContentInsets,
- outStableInsets, outOutsets)) {
+ outStableInsets, outOutsets, outDisplayCutout)) {
res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR;
}
@@ -1494,7 +1499,7 @@
// Don't do layout here, the window must call
// relayout to be displayed, so we'll do it there.
- displayContent.assignWindowLayers(false /* setLayoutNeeded */);
+ win.getParent().assignChildLayers();
if (focusChanged) {
mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);
@@ -1846,11 +1851,12 @@
}
public int relayoutWindow(Session session, IWindow client, int seq,
- WindowManager.LayoutParams attrs, int requestedWidth,
+ LayoutParams attrs, int requestedWidth,
int requestedHeight, int viewVisibility, int flags,
Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
- MergedConfiguration mergedConfiguration, Surface outSurface) {
+ DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
+ Surface outSurface) {
int result = 0;
boolean configChanged;
final boolean hasStatusBarPermission =
@@ -1963,6 +1969,13 @@
+ " newVis=" + viewVisibility, stack);
}
+ win.setDisplayLayoutNeeded();
+ win.mGivenInsetsPending = (flags & WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
+
+ // We may be deferring layout passes at the moment, but since the client is interested
+ // in the new out values right now we need to force a layout.
+ mWindowPlacerLocked.performSurfacePlacement(true /* force */);
+
// We should only relayout if the view is visible, it is a starting window, or the
// associated appToken is not hidden.
final boolean shouldRelayout = viewVisibility == View.VISIBLE &&
@@ -1972,15 +1985,6 @@
if (shouldRelayout) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");
- // We are about to create a surface, but we didn't run a layout yet. So better run
- // a layout now that we already know the right size, as a resize call will make the
- // surface transaction blocking until next vsync and slow us down.
- // TODO: Ideally we'd create the surface after running layout a bit further down,
- // but moving this seems to be too risky at this point in the release.
- if (win.mLayoutSeq == -1) {
- win.setDisplayLayoutNeeded();
- mWindowPlacerLocked.performSurfacePlacement(true);
- }
result = win.relayoutVisibleWindow(result, attrChanges, oldVisibility);
try {
@@ -2082,16 +2086,11 @@
mUnknownAppVisibilityController.notifyRelayouted(win.mAppToken);
}
- win.setDisplayLayoutNeeded();
- win.mGivenInsetsPending = (flags & WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
"relayoutWindow: updateOrientationFromAppTokens");
configChanged = updateOrientationFromAppTokensLocked(false, displayId);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- // We may be deferring layout passes at the moment, but since the client is interested
- // in the new out values right now we need to force a layout.
- mWindowPlacerLocked.performSurfacePlacement(true /* force */);
if (toBeDisplayed && win.mIsWallpaper) {
DisplayInfo displayInfo = win.getDisplayContent().getDisplayInfo();
dc.mWallpaperController.updateWallpaperOffset(
@@ -2135,6 +2134,7 @@
win.mLastRelayoutContentInsets.set(win.mContentInsets);
outVisibleInsets.set(win.mVisibleInsets);
outStableInsets.set(win.mStableInsets);
+ outCutout.set(win.mDisplayCutout);
outOutsets.set(win.mOutsets);
outBackdropFrame.set(win.getBackdropFrame(win.mFrame));
if (localLOGV) Slog.v(
@@ -3046,11 +3046,6 @@
}
@Override
- public boolean inKeyguardRestrictedInputMode() {
- return mPolicy.inKeyguardRestrictedKeyInputMode();
- }
-
- @Override
public boolean isKeyguardLocked() {
return mPolicy.isKeyguardLocked();
}
@@ -3691,9 +3686,8 @@
}
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper");
- return screenshotApplications(null /* appToken */, DEFAULT_DISPLAY, -1 /* width */,
- -1 /* height */, true /* includeFullDisplay */, 1f /* frameScale */,
- Bitmap.Config.ARGB_8888, true /* wallpaperOnly */, false /* includeDecor */);
+ return screenshotApplications(DEFAULT_DISPLAY, Bitmap.Config.ARGB_8888,
+ true /* wallpaperOnly */);
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
@@ -3712,10 +3706,8 @@
}
FgThread.getHandler().post(() -> {
- Bitmap bm = screenshotApplications(null /* appToken */, DEFAULT_DISPLAY,
- -1 /* width */, -1 /* height */, true /* includeFullDisplay */,
- 1f /* frameScale */, Bitmap.Config.ARGB_8888, false /* wallpaperOnly */,
- false /* includeDecor */);
+ Bitmap bm = screenshotApplications(DEFAULT_DISPLAY, Bitmap.Config.ARGB_8888,
+ false /* wallpaperOnly */);
try {
receiver.onHandleAssistScreenshot(bm);
} catch (RemoteException e) {
@@ -3749,29 +3741,21 @@
* In portrait mode, it grabs the full screenshot.
*
* @param displayId the Display to take a screenshot of.
- * @param width the width of the target bitmap
- * @param height the height of the target bitmap
- * @param includeFullDisplay true if the screen should not be cropped before capture
- * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
* @param config of the output bitmap
* @param wallpaperOnly true if only the wallpaper layer should be included in the screenshot
- * @param includeDecor whether to include window decors, like the status or navigation bar
- * background of the window
*/
- private Bitmap screenshotApplications(IBinder appToken, int displayId, int width,
- int height, boolean includeFullDisplay, float frameScale, Bitmap.Config config,
- boolean wallpaperOnly, boolean includeDecor) {
+ private Bitmap screenshotApplications(int displayId, Bitmap.Config config,
+ boolean wallpaperOnly) {
final DisplayContent displayContent;
synchronized(mWindowMap) {
displayContent = mRoot.getDisplayContentOrCreate(displayId);
if (displayContent == null) {
- if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + appToken
- + ": returning null. No Display for displayId=" + displayId);
+ if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot returning null. No Display for "
+ + "displayId=" + displayId);
return null;
}
}
- return displayContent.screenshotApplications(appToken, width, height,
- includeFullDisplay, frameScale, config, wallpaperOnly, includeDecor);
+ return displayContent.screenshotDisplay(config, wallpaperOnly);
}
/**
@@ -5874,6 +5858,7 @@
Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
}
+ mLatencyTracker.onActionStart(ACTION_ROTATE_SCREEN);
// TODO(multidisplay): rotation on non-default displays
if (CUSTOM_SCREEN_ROTATION && displayContent.isDefaultDisplay) {
mExitAnimId = exitAnim;
@@ -5998,6 +5983,7 @@
if (configChanged) {
mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayId).sendToTarget();
}
+ mLatencyTracker.onActionEnd(ACTION_ROTATE_SCREEN);
}
static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 90e9c23..e38605d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -42,7 +42,6 @@
import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
@@ -50,6 +49,7 @@
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -58,6 +58,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
@@ -143,6 +144,7 @@
import android.util.Slog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IApplicationToken;
@@ -184,7 +186,6 @@
// to capture touch events in that area.
static final int RESIZE_HANDLE_WIDTH_IN_DP = 30;
- final WindowManagerService mService;
final WindowManagerPolicy mPolicy;
final Context mContext;
final Session mSession;
@@ -319,6 +320,11 @@
private final Rect mLastOutsets = new Rect();
private boolean mOutsetsChanged = false;
+ /** Part of the display that has been cut away. See {@link DisplayCutout}. */
+ DisplayCutout mDisplayCutout = DisplayCutout.NO_CUTOUT;
+ private DisplayCutout mLastDisplayCutout = DisplayCutout.NO_CUTOUT;
+ private boolean mDisplayCutoutChanged;
+
/**
* Set to true if we are waiting for this window to receive its
* given internal insets before laying out other windows based on it.
@@ -620,7 +626,7 @@
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow) {
- mService = service;
+ super(service);
mSession = s;
mClient = c;
mAppOp = appOp;
@@ -771,7 +777,7 @@
@Override
public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overscanFrame,
Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame,
- Rect outsetFrame) {
+ Rect outsetFrame, DisplayCutout displayCutout) {
if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) {
// This window is being replaced and either already got information that it's being
// removed or we are still waiting for some information. Because of this we don't
@@ -1008,6 +1014,10 @@
mVisibleFrame.offset(-layoutXDiff, -layoutYDiff);
mStableFrame.offset(-layoutXDiff, -layoutYDiff);
+ // TODO(roosa): Figure out what frame exactly this needs to be calculated with.
+ mDisplayCutout = displayCutout.calculateRelativeTo(mFrame);
+
+
mCompatFrame.set(mFrame);
if (mEnforceSizeCompat) {
// If there is a size compatibility scale being applied to the
@@ -1148,8 +1158,9 @@
mOutsetsChanged |= !mLastOutsets.equals(mOutsets);
mFrameSizeChanged |= (mLastFrame.width() != mFrame.width()) ||
(mLastFrame.height() != mFrame.height());
+ mDisplayCutoutChanged |= !mLastDisplayCutout.equals(mDisplayCutout);
return mOverscanInsetsChanged || mContentInsetsChanged || mVisibleInsetsChanged
- || mOutsetsChanged || mFrameSizeChanged;
+ || mOutsetsChanged || mFrameSizeChanged || mDisplayCutoutChanged;
}
/**
@@ -1194,6 +1205,7 @@
|| winAnimator.mSurfaceResized
|| mOutsetsChanged
|| mFrameSizeChanged
+ || mDisplayCutoutChanged
|| configChanged
|| dragResizingChanged
|| !isResizedWhileNotDragResizingReported()
@@ -1213,7 +1225,8 @@
+ " dragResizingChanged=" + dragResizingChanged
+ " resizedWhileNotDragResizingReported="
+ isResizedWhileNotDragResizingReported()
- + " reportOrientationChanged=" + mReportOrientationChanged);
+ + " reportOrientationChanged=" + mReportOrientationChanged
+ + " displayCutoutChanged=" + mDisplayCutoutChanged);
}
// If it's a dead window left on screen, and the configuration changed, there is nothing
@@ -2848,6 +2861,7 @@
final boolean reportDraw = mWinAnimator.mDrawState == DRAW_PENDING;
final boolean reportOrientation = mReportOrientationChanged;
final int displayId = getDisplayId();
+ final DisplayCutout displayCutout = mDisplayCutout;
if (mAttrs.type != WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
&& mClient instanceof IWindow.Stub) {
// To prevent deadlock simulate one-way call if win.mClient is a local object.
@@ -2857,7 +2871,7 @@
try {
dispatchResized(frame, overscanInsets, contentInsets, visibleInsets,
stableInsets, outsets, reportDraw, mergedConfiguration,
- reportOrientation, displayId);
+ reportOrientation, displayId, displayCutout);
} catch (RemoteException e) {
// Not a remote call, RemoteException won't be raised.
}
@@ -2865,7 +2879,8 @@
});
} else {
dispatchResized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets,
- outsets, reportDraw, mergedConfiguration, reportOrientation, displayId);
+ outsets, reportDraw, mergedConfiguration, reportOrientation, displayId,
+ displayCutout);
}
//TODO (multidisplay): Accessibility supported only for the default display.
@@ -2879,6 +2894,7 @@
mStableInsetsChanged = false;
mOutsetsChanged = false;
mFrameSizeChanged = false;
+ mDisplayCutoutChanged = false;
mResizedWhileNotDragResizingReported = true;
mWinAnimator.mSurfaceResized = false;
mReportOrientationChanged = false;
@@ -2921,14 +2937,16 @@
private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- MergedConfiguration mergedConfiguration, boolean reportOrientation, int displayId)
+ MergedConfiguration mergedConfiguration, boolean reportOrientation, int displayId,
+ DisplayCutout displayCutout)
throws RemoteException {
final boolean forceRelayout = isDragResizeChanged() || mResizedWhileNotDragResizing
|| reportOrientation;
mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
reportDraw, mergedConfiguration, getBackdropFrame(frame), forceRelayout,
- mPolicy.isNavBarForcedShownLw(this), displayId);
+ mPolicy.isNavBarForcedShownLw(this), displayId,
+ new DisplayCutout.ParcelableWrapper(displayCutout));
mDragResizingChangeReported = true;
}
@@ -3245,6 +3263,7 @@
pw.print(" stable="); mStableInsets.printShortString(pw);
pw.print(" surface="); mAttrs.surfaceInsets.printShortString(pw);
pw.print(" outsets="); mOutsets.printShortString(pw);
+ pw.print(" cutout=" + mDisplayCutout);
pw.println();
pw.print(prefix); pw.print("Lst insets: overscan=");
mLastOverscanInsets.printShortString(pw);
@@ -3253,6 +3272,7 @@
pw.print(" stable="); mLastStableInsets.printShortString(pw);
pw.print(" physical="); mLastOutsets.printShortString(pw);
pw.print(" outset="); mLastOutsets.printShortString(pw);
+ pw.print(" cutout=" + mLastDisplayCutout);
pw.println();
}
pw.print(prefix); pw.print(mWinAnimator); pw.println(":");
@@ -4110,9 +4130,6 @@
policyCrop.intersect(-mCompatFrame.left, -mCompatFrame.top,
displayInfo.logicalWidth - mCompatFrame.left,
displayInfo.logicalHeight - mCompatFrame.top);
- } else if (mLayer >= mService.mSystemDecorLayer) {
- // Above the decor layer is easy, just use the entire window
- policyCrop.set(0, 0, mCompatFrame.width(), mCompatFrame.height());
} else if (mDecorFrame.isEmpty()) {
// Windows without policy decor aren't cropped.
policyCrop.set(0, 0, mCompatFrame.width(), mCompatFrame.height());
@@ -4280,6 +4297,7 @@
mLastVisibleInsets.set(mVisibleInsets);
mLastStableInsets.set(mStableInsets);
mLastOutsets.set(mOutsets);
+ mLastDisplayCutout = mDisplayCutout;
}
// TODO: Hack to work around the number of states AppWindowToken needs to access without having
@@ -4333,40 +4351,23 @@
}
}
- boolean usesRelativeZOrdering() {
- if (!isChildWindow()) {
- return false;
- } else if (mAttrs.type == TYPE_APPLICATION_MEDIA_OVERLAY) {
- return true;
- } else {
- return false;
- }
- }
@Override
boolean shouldMagnify() {
if (mAttrs.type == TYPE_INPUT_METHOD ||
- mAttrs.type == TYPE_INPUT_METHOD_DIALOG) {
- return false;
- } else if (isScreenOverlay()) {
+ mAttrs.type == TYPE_INPUT_METHOD_DIALOG ||
+ mAttrs.type == TYPE_MAGNIFICATION_OVERLAY ||
+ mAttrs.type == TYPE_NAVIGATION_BAR ||
+ // It's tempting to wonder: Have we forgotten the rounded corners overlay?
+ // worry not: it's a fake TYPE_NAVIGATION_BAR_PANEL
+ mAttrs.type == TYPE_NAVIGATION_BAR_PANEL ||
+ mAttrs.type == TYPE_STATUS_BAR) {
return false;
}
return true;
}
@Override
- boolean isScreenOverlay() {
- // It's tempting to wonder: Have we forgotten the rounded corners overlay?
- // worry not: it's a fake TYPE_NAVIGATION_BAR.
- if (mAttrs.type == TYPE_MAGNIFICATION_OVERLAY ||
- mAttrs.type == TYPE_NAVIGATION_BAR ||
- mAttrs.type == TYPE_STATUS_BAR) {
- return true;
- }
- return false;
- }
-
- @Override
SurfaceSession getSession() {
if (mSession.mSurfaceSession != null) {
return mSession.mSurfaceSession;
@@ -4382,7 +4383,7 @@
@Override
SurfaceControl.Builder makeSurface() {
- return mToken.makeChildSurface(this);
+ return getParent().makeChildSurface(this);
}
private void applyDims(Dimmer dimmer) {
@@ -4424,4 +4425,28 @@
public boolean isDimming() {
return mIsDimming;
}
+
+ // TODO(b/70040778): We should aim to eliminate the last user of TYPE_APPLICATION_MEDIA
+ // then we can drop all negative layering on the windowing side and simply inherit
+ // the default implementation here.
+ public void assignChildLayers(Transaction t) {
+ int layer = 1;
+ for (int i = 0; i < mChildren.size(); i++) {
+ final WindowState w = mChildren.get(i);
+
+ // APPLICATION_MEDIA_OVERLAY needs to go above APPLICATION_MEDIA
+ // while they both need to go below the main window. However the
+ // 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);
+ } else if (w.mAttrs.type == TYPE_APPLICATION_MEDIA_OVERLAY) {
+ w.assignLayer(t, -1);
+ } else {
+ w.assignLayer(t, layer);
+ }
+ w.assignChildLayers(t);
+ layer++;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index d2b3748..54c84ea 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -602,13 +602,6 @@
return mWin.getDisplayContent().getDisplay().getLayerStack();
}
- void updateLayerStackInTransaction() {
- if (mSurfaceController != null) {
- mSurfaceController.setLayerStackInTransaction(
- getLayerStack());
- }
- }
-
void resetDrawState() {
mDrawState = DRAW_PENDING;
@@ -727,16 +720,6 @@
+ width + "x" + height + "), layer=" + mAnimLayer + " HIDE", false);
}
- // Start a new transaction and apply position & offset.
-
- mService.openSurfaceTransaction();
- try {
- mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top, false);
- mSurfaceController.setLayerStackInTransaction(getLayerStack());
- } finally {
- mService.closeSurfaceTransaction("createSurfaceLocked");
- }
-
mLastHidden = true;
if (WindowManagerService.localLOGV) Slog.v(TAG, "Created surface " + this);
@@ -871,11 +854,9 @@
void computeShownFrameLocked() {
final boolean selfTransformation = mHasLocalTransformation;
- Transformation attachedTransformation =
- (mParentWinAnimator != null && mParentWinAnimator.mHasLocalTransformation)
- ? mParentWinAnimator.mTransformation : null;
Transformation appTransformation = (mAppAnimator != null && mAppAnimator.hasTransformation)
? mAppAnimator.transformation : null;
+ Transformation wallpaperTargetTransformation = null;
// Wallpapers are animated based on the "real" window they
// are currently targeting.
@@ -885,9 +866,9 @@
if (wallpaperAnimator.mHasLocalTransformation &&
wallpaperAnimator.mAnimation != null &&
!wallpaperAnimator.mAnimation.getDetachWallpaper()) {
- attachedTransformation = wallpaperAnimator.mTransformation;
- if (DEBUG_WALLPAPER && attachedTransformation != null) {
- Slog.v(TAG, "WP target attached xform: " + attachedTransformation);
+ wallpaperTargetTransformation = wallpaperAnimator.mTransformation;
+ if (DEBUG_WALLPAPER && wallpaperTargetTransformation != null) {
+ Slog.v(TAG, "WP target attached xform: " + wallpaperTargetTransformation);
}
}
final AppWindowAnimator wpAppAnimator = wallpaperTarget.mAppToken == null ?
@@ -909,7 +890,7 @@
screenRotationAnimation != null && screenRotationAnimation.isAnimating();
mHasClipRect = false;
- if (selfTransformation || attachedTransformation != null
+ if (selfTransformation || wallpaperTargetTransformation != null
|| appTransformation != null || screenAnimation) {
// cache often used attributes locally
final Rect frame = mWin.mFrame;
@@ -939,18 +920,27 @@
if (selfTransformation) {
tmpMatrix.postConcat(mTransformation.getMatrix());
}
- if (attachedTransformation != null) {
- tmpMatrix.postConcat(attachedTransformation.getMatrix());
+
+ if (wallpaperTargetTransformation != null) {
+ tmpMatrix.postConcat(wallpaperTargetTransformation.getMatrix());
}
if (appTransformation != null) {
tmpMatrix.postConcat(appTransformation.getMatrix());
}
+ int left = frame.left;
+ int top = frame.top;
+ if (mWin.isChildWindow()) {
+ WindowState parent = mWin.getParentWindow();
+ left -= parent.mFrame.left;
+ top -= parent.mFrame.top;
+ }
+
// The translation that applies the position of the window needs to be applied at the
// end in case that other translations include scaling. Otherwise the scaling will
// affect this translation. But it needs to be set before the screen rotation animation
// so the pivot point is at the center of the screen for all windows.
- tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
+ tmpMatrix.postTranslate(left + mWin.mXOffset, top + mWin.mYOffset);
if (screenAnimation) {
tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
}
@@ -985,8 +975,8 @@
if (selfTransformation) {
mShownAlpha *= mTransformation.getAlpha();
}
- if (attachedTransformation != null) {
- mShownAlpha *= attachedTransformation.getAlpha();
+ if (wallpaperTargetTransformation != null) {
+ mShownAlpha *= wallpaperTargetTransformation.getAlpha();
}
if (appTransformation != null) {
mShownAlpha *= appTransformation.getAlpha();
@@ -1017,8 +1007,8 @@
&& (mShownAlpha == 1.0 || mShownAlpha == 0.0)) Slog.v(
TAG, "computeShownFrameLocked: Animating " + this + " mAlpha=" + mAlpha
+ " self=" + (selfTransformation ? mTransformation.getAlpha() : "null")
- + " attached=" + (attachedTransformation == null ?
- "null" : attachedTransformation.getAlpha())
+ + " attached=" + (wallpaperTargetTransformation == null ?
+ "null" : wallpaperTargetTransformation.getAlpha())
+ " app=" + (appTransformation == null ? "null" : appTransformation.getAlpha())
+ " screen=" + (screenAnimation ?
screenRotationAnimation.getEnterTransformation().getAlpha() : "null"));
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 62a2abb..5bcf59c 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -46,9 +46,6 @@
class WindowToken extends WindowContainer<WindowState> {
private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowToken" : TAG_WM;
- // The window manager!
- protected final WindowManagerService mService;
-
// The actual token.
final IBinder token;
@@ -107,7 +104,7 @@
WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
DisplayContent dc, boolean ownerCanManageAppTokens) {
- mService = service;
+ super(service);
token = _token;
windowType = type;
mPersistOnEmpty = persistOnEmpty;
@@ -125,6 +122,11 @@
}
void setExiting() {
+ if (mChildren.size() == 0) {
+ super.removeImmediately();
+ return;
+ }
+
// This token is exiting, so allow it to be removed when it no longer contains any windows.
mPersistOnEmpty = false;
@@ -255,12 +257,6 @@
// up with goodToGo, so we don't move a window
// to another display before the window behind
// it is ready.
- SurfaceControl.openTransaction();
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowState win = mChildren.get(i);
- win.mWinAnimator.updateLayerStackInTransaction();
- }
- SurfaceControl.closeTransaction();
super.onDisplayChanged(dc);
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
new file mode 100644
index 0000000..5d76304
--- /dev/null
+++ b/services/core/jni/Android.bp
@@ -0,0 +1,121 @@
+cc_library_static {
+ name: "libservices.core",
+ defaults: ["libservices.core-libs"],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-parameter",
+
+ "-DEGL_EGLEXT_PROTOTYPES",
+ "-DGL_GLEXT_PROTOTYPES",
+ ],
+
+ srcs: [
+ "BroadcastRadio/JavaRef.cpp",
+ "BroadcastRadio/NativeCallbackThread.cpp",
+ "BroadcastRadio/BroadcastRadioService.cpp",
+ "BroadcastRadio/Tuner.cpp",
+ "BroadcastRadio/TunerCallback.cpp",
+ "BroadcastRadio/convert.cpp",
+ "BroadcastRadio/regions.cpp",
+ "com_android_server_AlarmManagerService.cpp",
+ "com_android_server_am_BatteryStatsService.cpp",
+ "com_android_server_connectivity_Vpn.cpp",
+ "com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp",
+ "com_android_server_ConsumerIrService.cpp",
+ "com_android_server_HardwarePropertiesManagerService.cpp",
+ "com_android_server_hdmi_HdmiCecController.cpp",
+ "com_android_server_input_InputApplicationHandle.cpp",
+ "com_android_server_input_InputManagerService.cpp",
+ "com_android_server_input_InputWindowHandle.cpp",
+ "com_android_server_lights_LightsService.cpp",
+ "com_android_server_location_GnssLocationProvider.cpp",
+ "com_android_server_locksettings_SyntheticPasswordManager.cpp",
+ "com_android_server_power_PowerManagerService.cpp",
+ "com_android_server_SerialService.cpp",
+ "com_android_server_storage_AppFuseBridge.cpp",
+ "com_android_server_SystemServer.cpp",
+ "com_android_server_tv_TvUinputBridge.cpp",
+ "com_android_server_tv_TvInputHal.cpp",
+ "com_android_server_vr_VrManagerService.cpp",
+ "com_android_server_UsbDeviceManager.cpp",
+ "com_android_server_UsbDescriptorParser.cpp",
+ "com_android_server_UsbMidiDevice.cpp",
+ "com_android_server_UsbHostManager.cpp",
+ "com_android_server_VibratorService.cpp",
+ "com_android_server_PersistentDataBlockService.cpp",
+ "com_android_server_GraphicsStatsService.cpp",
+ "onload.cpp",
+ ],
+
+ include_dirs: [
+ "frameworks/base/libs",
+ "frameworks/native/services",
+ "system/gatekeeper/include",
+ ],
+}
+
+cc_defaults {
+ name: "libservices.core-libs",
+ shared_libs: [
+ "libandroid_runtime",
+ "libandroidfw",
+ "libaudioclient",
+ "libbase",
+ "libappfuse",
+ "libbinder",
+ "libcutils",
+ "libcrypto",
+ "liblog",
+ "libhardware",
+ "libhardware_legacy",
+ "libhidlbase",
+ "libkeystore_binder",
+ "libnativehelper",
+ "libutils",
+ "libui",
+ "libinput",
+ "libinputflinger",
+ "libinputservice",
+ "libschedulerservicehidl",
+ "libsensorservice",
+ "libsensorservicehidl",
+ "libgui",
+ "libusbhost",
+ "libsuspend",
+ "libEGL",
+ "libGLESv2",
+ "libnetutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "libhwui",
+ "android.hardware.audio.common@2.0",
+ "android.hardware.broadcastradio@1.0",
+ "android.hardware.broadcastradio@1.1",
+ "android.hardware.broadcastradio@1.2",
+ "android.hardware.contexthub@1.0",
+ "android.hardware.gnss@1.0",
+ "android.hardware.gnss@1.1",
+ "android.hardware.ir@1.0",
+ "android.hardware.light@2.0",
+ "android.hardware.power@1.0",
+ "android.hardware.power@1.1",
+ "android.hardware.tetheroffload.config@1.0",
+ "android.hardware.thermal@1.0",
+ "android.hardware.tv.cec@1.0",
+ "android.hardware.tv.input@1.0",
+ "android.hardware.vibrator@1.0",
+ "android.hardware.vibrator@1.1",
+ "android.hardware.vr@1.0",
+ "android.frameworks.schedulerservice@1.0",
+ "android.frameworks.sensorservice@1.0",
+ ],
+
+ static_libs: [
+ "android.hardware.broadcastradio@common-utils-lib",
+ "libscrypt_static",
+ ],
+}
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
deleted file mode 100644
index 4a2da37..0000000
--- a/services/core/jni/Android.mk
+++ /dev/null
@@ -1,113 +0,0 @@
-# This file is included by the top level services directory to collect source
-# files
-LOCAL_REL_DIR := core/jni
-
-LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter
-
-LOCAL_SRC_FILES += \
- $(LOCAL_REL_DIR)/BroadcastRadio/JavaRef.cpp \
- $(LOCAL_REL_DIR)/BroadcastRadio/NativeCallbackThread.cpp \
- $(LOCAL_REL_DIR)/BroadcastRadio/BroadcastRadioService.cpp \
- $(LOCAL_REL_DIR)/BroadcastRadio/Tuner.cpp \
- $(LOCAL_REL_DIR)/BroadcastRadio/TunerCallback.cpp \
- $(LOCAL_REL_DIR)/BroadcastRadio/convert.cpp \
- $(LOCAL_REL_DIR)/BroadcastRadio/regions.cpp \
- $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_am_BatteryStatsService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
- $(LOCAL_REL_DIR)/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp \
- $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_HardwarePropertiesManagerService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \
- $(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
- $(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \
- $(LOCAL_REL_DIR)/com_android_server_lights_LightsService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_location_GnssLocationProvider.cpp \
- $(LOCAL_REL_DIR)/com_android_server_locksettings_SyntheticPasswordManager.cpp \
- $(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_storage_AppFuseBridge.cpp \
- $(LOCAL_REL_DIR)/com_android_server_SystemServer.cpp \
- $(LOCAL_REL_DIR)/com_android_server_tv_TvUinputBridge.cpp \
- $(LOCAL_REL_DIR)/com_android_server_tv_TvInputHal.cpp \
- $(LOCAL_REL_DIR)/com_android_server_vr_VrManagerService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \
- $(LOCAL_REL_DIR)/com_android_server_UsbDescriptorParser.cpp \
- $(LOCAL_REL_DIR)/com_android_server_UsbMidiDevice.cpp \
- $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \
- $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_PersistentDataBlockService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_GraphicsStatsService.cpp \
- $(LOCAL_REL_DIR)/onload.cpp
-
-LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE) \
- external/scrypt/lib/crypto \
- frameworks/base/services \
- frameworks/base/libs \
- frameworks/base/core/jni \
- frameworks/native/services \
- system/core/libappfuse/include \
- system/gatekeeper/include \
- system/security/keystore/include \
- $(call include-path-for, libhardware)/hardware \
- $(call include-path-for, libhardware_legacy)/hardware_legacy \
-
-LOCAL_SHARED_LIBRARIES += \
- libandroid_runtime \
- libandroidfw \
- libaudioclient \
- libbase \
- libappfuse \
- libbinder \
- libcutils \
- libcrypto \
- liblog \
- libhardware \
- libhardware_legacy \
- libhidlbase \
- libkeystore_binder \
- libnativehelper \
- libutils \
- libui \
- libinput \
- libinputflinger \
- libinputservice \
- libschedulerservicehidl \
- libsensorservice \
- libsensorservicehidl \
- libgui \
- libusbhost \
- libsuspend \
- libEGL \
- libGLESv2 \
- libnetutils \
- libhidlbase \
- libhidltransport \
- libhwbinder \
- libutils \
- libhwui \
- android.hardware.audio.common@2.0 \
- android.hardware.broadcastradio@1.0 \
- android.hardware.broadcastradio@1.1 \
- android.hardware.broadcastradio@1.2 \
- android.hardware.contexthub@1.0 \
- android.hardware.gnss@1.0 \
- android.hardware.ir@1.0 \
- android.hardware.light@2.0 \
- android.hardware.power@1.0 \
- android.hardware.power@1.1 \
- android.hardware.tetheroffload.config@1.0 \
- android.hardware.thermal@1.0 \
- android.hardware.tv.cec@1.0 \
- android.hardware.tv.input@1.0 \
- android.hardware.vibrator@1.0 \
- android.hardware.vibrator@1.1 \
- android.hardware.vr@1.0 \
- android.frameworks.schedulerservice@1.0 \
- android.frameworks.sensorservice@1.0 \
-
-LOCAL_STATIC_LIBRARIES += \
- android.hardware.broadcastradio@common-utils-lib \
- libscrypt_static \
diff --git a/services/core/jni/com_android_server_UsbDescriptorParser.cpp b/services/core/jni/com_android_server_UsbDescriptorParser.cpp
index df85e31..35e65bc 100644
--- a/services/core/jni/com_android_server_UsbDescriptorParser.cpp
+++ b/services/core/jni/com_android_server_UsbDescriptorParser.cpp
@@ -17,16 +17,18 @@
#define LOG_TAG "UsbHostManagerJNI"
#include "utils/Log.h"
+#include <stdlib.h>
+
#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include <usbhost/usbhost.h>
-#define MAX_DESCRIPTORS_LENGTH 16384
+#define MAX_DESCRIPTORS_LENGTH 4096
// com.android.server.usb.descriptors
extern "C" {
-jbyteArray JNICALL Java_com_android_server_usb_descriptors_UsbDescriptorParser_getRawDescriptors(
+jbyteArray JNICALL Java_com_android_server_usb_descriptors_UsbDescriptorParser_getRawDescriptors_1native(
JNIEnv* env, jobject thiz, jstring deviceAddr) {
const char *deviceAddrStr = env->GetStringUTFChars(deviceAddr, NULL);
struct usb_device* device = usb_device_open(deviceAddrStr);
@@ -39,6 +41,7 @@
int fd = usb_device_get_fd(device);
if (fd < 0) {
+ usb_device_close(device);
return NULL;
}
@@ -46,17 +49,48 @@
jbyte buffer[MAX_DESCRIPTORS_LENGTH];
lseek(fd, 0, SEEK_SET);
int numBytes = read(fd, buffer, sizeof(buffer));
-
+ jbyteArray ret = NULL;
usb_device_close(device);
- jbyteArray ret = NULL;
- if (numBytes != 0) {
+ if (numBytes > 0) {
ret = env->NewByteArray(numBytes);
env->SetByteArrayRegion(ret, 0, numBytes, buffer);
+ } else {
+ ALOGE("error reading descriptors\n");
}
+
return ret;
}
+jstring JNICALL Java_com_android_server_usb_descriptors_UsbDescriptorParser_getDescriptorString_1native(
+ JNIEnv* env, jobject thiz, jstring deviceAddr, jint stringId) {
+
+ const char *deviceAddrStr = env->GetStringUTFChars(deviceAddr, NULL);
+ struct usb_device* device = usb_device_open(deviceAddrStr);
+ env->ReleaseStringUTFChars(deviceAddr, deviceAddrStr);
+
+ if (!device) {
+ ALOGE("usb_device_open failed");
+ return NULL;
+ }
+
+ int fd = usb_device_get_fd(device);
+ if (fd < 0) {
+ ALOGE("usb_device_get_fd failed");
+ usb_device_close(device);
+ return NULL;
+ }
+
+ char* c_str = usb_device_get_string(device, stringId, 0 /*timeout*/);
+
+ jstring j_str = env->NewStringUTF(c_str);
+
+ free(c_str);
+ usb_device_close(device);
+
+ return j_str;
+}
+
} // extern "C"
diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp
index 88ae824..24f2014 100644
--- a/services/core/jni/com_android_server_UsbHostManager.cpp
+++ b/services/core/jni/com_android_server_UsbHostManager.cpp
@@ -22,8 +22,6 @@
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
-#include <usbhost/usbhost.h>
-
#include <stdio.h>
#include <asm/byteorder.h>
#include <sys/types.h>
@@ -31,22 +29,20 @@
#include <fcntl.h>
#include <sys/ioctl.h>
+#include <usbhost/usbhost.h>
+
+#define MAX_DESCRIPTORS_LENGTH 4096
+
namespace android
{
-static const int USB_CONTROL_TRANSFER_TIMEOUT_MS = 200;
-
static struct parcel_file_descriptor_offsets_t
{
jclass mClass;
jmethodID mConstructor;
} gParcelFileDescriptorOffsets;
-static jmethodID method_beginUsbDeviceAdded;
-static jmethodID method_addUsbConfiguration;
-static jmethodID method_addUsbInterface;
-static jmethodID method_addUsbEndpoint;
-static jmethodID method_endUsbDeviceAdded;
+static jmethodID method_usbDeviceAdded;
static jmethodID method_usbDeviceRemoved;
static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
@@ -57,101 +53,52 @@
}
}
-static int usb_device_added(const char *devname, void* client_data) {
- struct usb_descriptor_header* desc;
- struct usb_descriptor_iter iter;
-
- struct usb_device *device = usb_device_open(devname);
+static int usb_device_added(const char *devAddress, void* clientData) {
+ struct usb_device *device = usb_device_open(devAddress);
if (!device) {
ALOGE("usb_device_open failed\n");
return 0;
}
- JNIEnv* env = AndroidRuntime::getJNIEnv();
- jobject thiz = (jobject)client_data;
const usb_device_descriptor* deviceDesc = usb_device_get_device_descriptor(device);
+ int classID = deviceDesc->bDeviceClass;
+ int subClassID = deviceDesc->bDeviceSubClass;
- char *manufacturer = usb_device_get_manufacturer_name(device,
- USB_CONTROL_TRANSFER_TIMEOUT_MS);
- char *product = usb_device_get_product_name(device,
- USB_CONTROL_TRANSFER_TIMEOUT_MS);
- int version = usb_device_get_version(device);
- char *serial = usb_device_get_serial(device,
- USB_CONTROL_TRANSFER_TIMEOUT_MS);
+ // get the raw descriptors
+ int numBytes = usb_device_get_descriptors_length(device);
+ if (numBytes > 0) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jobject thiz = (jobject)clientData;
+ jstring deviceAddress = env->NewStringUTF(devAddress);
- jstring deviceName = env->NewStringUTF(devname);
- jstring manufacturerName = AndroidRuntime::NewStringLatin1(env, manufacturer);
- jstring productName = AndroidRuntime::NewStringLatin1(env, product);
- jstring serialNumber = AndroidRuntime::NewStringLatin1(env, serial);
+ jbyteArray descriptorsArray = env->NewByteArray(numBytes);
+ const jbyte* rawDescriptors = (const jbyte*)usb_device_get_raw_descriptors(device);
+ env->SetByteArrayRegion(descriptorsArray, 0, numBytes, rawDescriptors);
- jboolean result = env->CallBooleanMethod(thiz, method_beginUsbDeviceAdded,
- deviceName, usb_device_get_vendor_id(device), usb_device_get_product_id(device),
- deviceDesc->bDeviceClass, deviceDesc->bDeviceSubClass, deviceDesc->bDeviceProtocol,
- manufacturerName, productName, version, serialNumber);
+ env->CallBooleanMethod(thiz, method_usbDeviceAdded,
+ deviceAddress, classID, subClassID, descriptorsArray);
- env->DeleteLocalRef(serialNumber);
- env->DeleteLocalRef(productName);
- env->DeleteLocalRef(manufacturerName);
- env->DeleteLocalRef(deviceName);
- free(manufacturer);
- free(product);
- free(serial);
+ env->DeleteLocalRef(descriptorsArray);
+ env->DeleteLocalRef(deviceAddress);
- if (!result) goto fail;
-
- usb_descriptor_iter_init(device, &iter);
-
- while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {
- if (desc->bDescriptorType == USB_DT_CONFIG) {
- struct usb_config_descriptor *config = (struct usb_config_descriptor *)desc;
- char *name = usb_device_get_string(device, config->iConfiguration,
- USB_CONTROL_TRANSFER_TIMEOUT_MS);
- jstring configName = AndroidRuntime::NewStringLatin1(env, name);
-
- env->CallVoidMethod(thiz, method_addUsbConfiguration,
- config->bConfigurationValue, configName, config->bmAttributes,
- config->bMaxPower);
-
- env->DeleteLocalRef(configName);
- free(name);
- } else if (desc->bDescriptorType == USB_DT_INTERFACE) {
- struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;
- char *name = usb_device_get_string(device, interface->iInterface,
- USB_CONTROL_TRANSFER_TIMEOUT_MS);
- jstring interfaceName = AndroidRuntime::NewStringLatin1(env, name);
-
- env->CallVoidMethod(thiz, method_addUsbInterface,
- interface->bInterfaceNumber, interfaceName, interface->bAlternateSetting,
- interface->bInterfaceClass, interface->bInterfaceSubClass,
- interface->bInterfaceProtocol);
-
- env->DeleteLocalRef(interfaceName);
- free(name);
- } else if (desc->bDescriptorType == USB_DT_ENDPOINT) {
- struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)desc;
-
- env->CallVoidMethod(thiz, method_addUsbEndpoint,
- endpoint->bEndpointAddress, endpoint->bmAttributes,
- __le16_to_cpu(endpoint->wMaxPacketSize), endpoint->bInterval);
- }
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ } else {
+ // TODO return an error code here?
+ ALOGE("error reading descriptors\n");
}
- env->CallVoidMethod(thiz, method_endUsbDeviceAdded);
-
-fail:
usb_device_close(device);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
return 0;
}
-static int usb_device_removed(const char *devname, void* client_data) {
+static int usb_device_removed(const char *devAddress, void* clientData) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
- jobject thiz = (jobject)client_data;
+ jobject thiz = (jobject)clientData;
- jstring deviceName = env->NewStringUTF(devname);
- env->CallVoidMethod(thiz, method_usbDeviceRemoved, deviceName);
- env->DeleteLocalRef(deviceName);
+ jstring deviceAddress = env->NewStringUTF(devAddress);
+ env->CallVoidMethod(thiz, method_usbDeviceRemoved, deviceAddress);
+ env->DeleteLocalRef(deviceAddress);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return 0;
}
@@ -168,11 +115,11 @@
}
static jobject android_server_UsbHostManager_openDevice(JNIEnv *env, jobject /* thiz */,
- jstring deviceName)
+ jstring deviceAddress)
{
- const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);
- struct usb_device* device = usb_device_open(deviceNameStr);
- env->ReleaseStringUTFChars(deviceName, deviceNameStr);
+ const char *deviceAddressStr = env->GetStringUTFChars(deviceAddress, NULL);
+ struct usb_device* device = usb_device_open(deviceAddressStr);
+ env->ReleaseStringUTFChars(deviceAddress, deviceAddressStr);
if (!device)
return NULL;
@@ -206,34 +153,12 @@
ALOGE("Can't find com/android/server/usb/UsbHostManager");
return -1;
}
- method_beginUsbDeviceAdded = env->GetMethodID(clazz, "beginUsbDeviceAdded",
- "(Ljava/lang/String;IIIIILjava/lang/String;Ljava/lang/String;ILjava/lang/String;)Z");
- if (method_beginUsbDeviceAdded == NULL) {
+ method_usbDeviceAdded =
+ env->GetMethodID(clazz, "usbDeviceAdded", "(Ljava/lang/String;II[B)Z");
+ if (method_usbDeviceAdded == NULL) {
ALOGE("Can't find beginUsbDeviceAdded");
return -1;
}
- method_addUsbConfiguration = env->GetMethodID(clazz, "addUsbConfiguration",
- "(ILjava/lang/String;II)V");
- if (method_addUsbConfiguration == NULL) {
- ALOGE("Can't find addUsbConfiguration");
- return -1;
- }
- method_addUsbInterface = env->GetMethodID(clazz, "addUsbInterface",
- "(ILjava/lang/String;IIII)V");
- if (method_addUsbInterface == NULL) {
- ALOGE("Can't find addUsbInterface");
- return -1;
- }
- method_addUsbEndpoint = env->GetMethodID(clazz, "addUsbEndpoint", "(IIII)V");
- if (method_addUsbEndpoint == NULL) {
- ALOGE("Can't find addUsbEndpoint");
- return -1;
- }
- method_endUsbDeviceAdded = env->GetMethodID(clazz, "endUsbDeviceAdded", "()V");
- if (method_endUsbDeviceAdded == NULL) {
- ALOGE("Can't find endUsbDeviceAdded");
- return -1;
- }
method_usbDeviceRemoved = env->GetMethodID(clazz, "usbDeviceRemoved",
"(Ljava/lang/String;)V");
if (method_usbDeviceRemoved == NULL) {
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index ae7d6da..39cc953 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -43,13 +43,14 @@
using android::hardware::Return;
using android::hardware::Void;
-using android::hardware::power::V1_0::IPower;
using android::hardware::power::V1_0::PowerStatePlatformSleepState;
using android::hardware::power::V1_0::PowerStateVoter;
using android::hardware::power::V1_0::Status;
using android::hardware::power::V1_1::PowerStateSubsystem;
using android::hardware::power::V1_1::PowerStateSubsystemSleepState;
using android::hardware::hidl_vec;
+using IPowerV1_1 = android::hardware::power::V1_1::IPower;
+using IPowerV1_0 = android::hardware::power::V1_0::IPower;
namespace android
{
@@ -59,9 +60,9 @@
static bool wakeup_init = false;
static sem_t wakeup_sem;
-extern sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0;
-extern std::mutex gPowerHalMutex;
-extern bool getPowerHal();
+extern sp<IPowerV1_0> getPowerHalV1_0();
+extern sp<IPowerV1_1> getPowerHalV1_1();
+extern bool processPowerHalReturn(const Return<void> &ret, const char* functionName);
// Java methods used in getLowPowerStats
static jmethodID jgetAndUpdatePlatformState = NULL;
@@ -203,13 +204,13 @@
return;
}
- std::lock_guard<std::mutex> lock(gPowerHalMutex);
- if (!getPowerHal()) {
+ sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
+ if (powerHalV1_0 == nullptr) {
ALOGE("Power Hal not loaded");
return;
}
- Return<void> ret = gPowerHalV1_0->getPlatformLowPowerStats(
+ Return<void> ret = powerHalV1_0->getPlatformLowPowerStats(
[&env, &jrpmStats](hidl_vec<PowerStatePlatformSleepState> states, Status status) {
if (status != Status::SUCCESS) return;
@@ -236,20 +237,17 @@
}
}
});
- if (!ret.isOk()) {
- ALOGE("getLowPowerStats() failed: power HAL service not available");
- gPowerHalV1_0 = nullptr;
+ if (!processPowerHalReturn(ret, "getPlatformLowPowerStats")) {
return;
}
- //Trying to cast to IPower 1.1, this will succeed only for devices supporting 1.1
- sp<android::hardware::power::V1_1::IPower> gPowerHal_1_1
- = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
- if (gPowerHal_1_1 == nullptr) {
- //This device does not support IPower@1.1, exiting gracefully
+ // Trying to get IPower 1.1, this will succeed only for devices supporting 1.1
+ sp<IPowerV1_1> powerHal_1_1 = getPowerHalV1_1();
+ if (powerHal_1_1 == nullptr) {
+ // This device does not support IPower@1.1, exiting gracefully
return;
}
- ret = gPowerHal_1_1->getSubsystemLowPowerStats(
+ ret = powerHal_1_1->getSubsystemLowPowerStats(
[&env, &jrpmStats](hidl_vec<PowerStateSubsystem> subsystems, Status status) {
if (status != Status::SUCCESS) return;
@@ -275,11 +273,7 @@
}
}
});
- if (!ret.isOk()) {
- ALOGE("getSubsystemLowPowerStats() failed: power HAL service not available");
- gPowerHalV1_0 = nullptr;
- }
- // gPowerHalMutex released here
+ processPowerHalReturn(ret, "getSubsystemLowPowerStats");
}
static jint getPlatformLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject outBuf) {
@@ -294,13 +288,13 @@
}
{
- std::lock_guard<std::mutex> lock(gPowerHalMutex);
- if (!getPowerHal()) {
+ sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
+ if (powerHalV1_0 == nullptr) {
ALOGE("Power Hal not loaded");
return -1;
}
- Return<void> ret = gPowerHalV1_0->getPlatformLowPowerStats(
+ Return<void> ret = powerHalV1_0->getPlatformLowPowerStats(
[&offset, &remaining, &total_added](hidl_vec<PowerStatePlatformSleepState> states,
Status status) {
if (status != Status::SUCCESS)
@@ -352,9 +346,7 @@
}
);
- if (!ret.isOk()) {
- ALOGE("getPlatformLowPowerStats() failed: power HAL service not available");
- gPowerHalV1_0 = nullptr;
+ if (!processPowerHalReturn(ret, "getPlatformLowPowerStats")) {
return -1;
}
}
@@ -369,8 +361,8 @@
int remaining = (int)env->GetDirectBufferCapacity(outBuf);
int total_added = -1;
- //This is a IPower 1.1 API
- sp<android::hardware::power::V1_1::IPower> gPowerHal_1_1 = nullptr;
+ // This is a IPower 1.1 API
+ sp<IPowerV1_1> powerHal_1_1 = nullptr;
if (outBuf == NULL) {
jniThrowException(env, "java/lang/NullPointerException", "null argument");
@@ -378,20 +370,14 @@
}
{
- std::lock_guard<std::mutex> lock(gPowerHalMutex);
- if (!getPowerHal()) {
- ALOGE("Power Hal not loaded");
- return -1;
- }
-
- //Trying to cast to 1.1, this will succeed only for devices supporting 1.1
- gPowerHal_1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
- if (gPowerHal_1_1 == nullptr) {
+ // Trying to get 1.1, this will succeed only for devices supporting 1.1
+ powerHal_1_1 = getPowerHalV1_1();
+ if (powerHal_1_1 == nullptr) {
//This device does not support IPower@1.1, exiting gracefully
return 0;
- }
+ }
- Return<void> ret = gPowerHal_1_1->getSubsystemLowPowerStats(
+ Return<void> ret = powerHal_1_1->getSubsystemLowPowerStats(
[&offset, &remaining, &total_added](hidl_vec<PowerStateSubsystem> subsystems,
Status status) {
@@ -452,9 +438,7 @@
}
);
- if (!ret.isOk()) {
- ALOGE("getSubsystemLowPowerStats() failed: power HAL service not available");
- gPowerHalV1_0 = nullptr;
+ if (!processPowerHalReturn(ret, "getSubsystemLowPowerStats")) {
return -1;
}
}
diff --git a/services/core/jni/com_android_server_input_InputApplicationHandle.cpp b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
index 232b2c2..514b6e1 100644
--- a/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
+++ b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
@@ -65,11 +65,11 @@
gInputApplicationHandleClassInfo.name));
if (nameObj) {
const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
- mInfo->name.setTo(nameStr);
+ mInfo->name = nameStr;
env->ReleaseStringUTFChars(nameObj, nameStr);
env->DeleteLocalRef(nameObj);
} else {
- mInfo->name.setTo("<null>");
+ mInfo->name = "<null>";
}
mInfo->dispatchingTimeout = env->GetLongField(obj,
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 21300ed..27c2fac 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -32,6 +32,7 @@
#include <atomic>
#include <cinttypes>
#include <limits.h>
+#include <android-base/stringprintf.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
@@ -65,6 +66,8 @@
#define INDENT " "
+using android::base::StringPrintf;
+
namespace android {
// The exponent used to calculate the pointer speed scaling factor.
@@ -198,7 +201,7 @@
inline sp<InputManager> getInputManager() const { return mInputManager; }
- void dump(String8& dump);
+ void dump(std::string& dump);
void setVirtualDisplayViewports(JNIEnv* env, jobjectArray viewportObjArray);
void setDisplayViewport(int32_t viewportType, const DisplayViewport& viewport);
@@ -240,7 +243,7 @@
virtual void notifyConfigurationChanged(nsecs_t when);
virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
const sp<InputWindowHandle>& inputWindowHandle,
- const String8& reason);
+ const std::string& reason);
virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle);
virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags);
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig);
@@ -347,28 +350,28 @@
env->DeleteGlobalRef(mServiceObj);
}
-void NativeInputManager::dump(String8& dump) {
- dump.append("Input Manager State:\n");
+void NativeInputManager::dump(std::string& dump) {
+ dump += "Input Manager State:\n";
{
- dump.appendFormat(INDENT "Interactive: %s\n", toString(mInteractive.load()));
+ dump += StringPrintf(INDENT "Interactive: %s\n", toString(mInteractive.load()));
}
{
AutoMutex _l(mLock);
- dump.appendFormat(INDENT "System UI Visibility: 0x%0" PRIx32 "\n",
+ dump += StringPrintf(INDENT "System UI Visibility: 0x%0" PRIx32 "\n",
mLocked.systemUiVisibility);
- dump.appendFormat(INDENT "Pointer Speed: %" PRId32 "\n", mLocked.pointerSpeed);
- dump.appendFormat(INDENT "Pointer Gestures Enabled: %s\n",
+ dump += StringPrintf(INDENT "Pointer Speed: %" PRId32 "\n", mLocked.pointerSpeed);
+ dump += StringPrintf(INDENT "Pointer Gestures Enabled: %s\n",
toString(mLocked.pointerGesturesEnabled));
- dump.appendFormat(INDENT "Show Touches: %s\n", toString(mLocked.showTouches));
- dump.appendFormat(INDENT "Pointer Capture Enabled: %s\n", toString(mLocked.pointerCapture));
+ dump += StringPrintf(INDENT "Show Touches: %s\n", toString(mLocked.showTouches));
+ dump += StringPrintf(INDENT "Pointer Capture Enabled: %s\n", toString(mLocked.pointerCapture));
}
- dump.append("\n");
+ dump += "\n";
mInputManager->getReader()->dump(dump);
- dump.append("\n");
+ dump += "\n";
mInputManager->getDispatcher()->dump(dump);
- dump.append("\n");
+ dump += "\n";
}
bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
@@ -668,7 +671,7 @@
}
nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<InputWindowHandle>& inputWindowHandle, const String8& reason) {
+ const sp<InputWindowHandle>& inputWindowHandle, const std::string& reason) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("notifyANR");
#endif
@@ -680,7 +683,7 @@
getInputApplicationHandleObjLocalRef(env, inputApplicationHandle);
jobject inputWindowHandleObj =
getInputWindowHandleObjLocalRef(env, inputWindowHandle);
- jstring reasonObj = env->NewStringUTF(reason.string());
+ jstring reasonObj = env->NewStringUTF(reason.c_str());
jlong newTimeout = env->CallLongMethod(mServiceObj,
gServiceClassInfo.notifyANR, inputApplicationHandleObj, inputWindowHandleObj,
@@ -1342,7 +1345,7 @@
NativeInputManager* im = static_cast<NativeInputManager*>(data);
ALOGW("Input channel object '%s' was disposed without first being unregistered with "
- "the input manager!", inputChannel->getName().string());
+ "the input manager!", inputChannel->getName().c_str());
im->unregisterInputChannel(env, inputChannel);
}
@@ -1363,9 +1366,9 @@
status_t status = im->registerInputChannel(
env, inputChannel, inputWindowHandle, monitor);
if (status) {
- String8 message;
- message.appendFormat("Failed to register input channel. status=%d", status);
- jniThrowRuntimeException(env, message.string());
+ std::string message;
+ message += StringPrintf("Failed to register input channel. status=%d", status);
+ jniThrowRuntimeException(env, message.c_str());
return;
}
@@ -1390,9 +1393,9 @@
status_t status = im->unregisterInputChannel(env, inputChannel);
if (status && status != BAD_VALUE) { // ignore already unregistered channel
- String8 message;
- message.appendFormat("Failed to unregister input channel. status=%d", status);
- jniThrowRuntimeException(env, message.string());
+ std::string message;
+ message += StringPrintf("Failed to unregister input channel. status=%d", status);
+ jniThrowRuntimeException(env, message.c_str());
}
}
@@ -1576,9 +1579,9 @@
static jstring nativeDump(JNIEnv* env, jclass /* clazz */, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
- String8 dump;
+ std::string dump;
im->dump(dump);
- return env->NewStringUTF(dump.string());
+ return env->NewStringUTF(dump.c_str());
}
static void nativeMonitor(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
diff --git a/services/core/jni/com_android_server_input_InputWindowHandle.cpp b/services/core/jni/com_android_server_input_InputWindowHandle.cpp
index 2b2a6fa..c13aa38 100644
--- a/services/core/jni/com_android_server_input_InputWindowHandle.cpp
+++ b/services/core/jni/com_android_server_input_InputWindowHandle.cpp
@@ -103,11 +103,11 @@
gInputWindowHandleClassInfo.name));
if (nameObj) {
const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
- mInfo->name.setTo(nameStr);
+ mInfo->name = nameStr;
env->ReleaseStringUTFChars(nameObj, nameStr);
env->DeleteLocalRef(nameObj);
} else {
- mInfo->name.setTo("<null>");
+ mInfo->name = "<null>";
}
mInfo->layoutParamsFlags = env->GetIntField(obj,
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index daf3f2f..4cbe64d 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -18,7 +18,7 @@
#define LOG_NDEBUG 0
-#include <android/hardware/gnss/1.0/IGnss.h>
+#include <android/hardware/gnss/1.1/IGnss.h>
#include <nativehelper/JNIHelp.h>
#include "jni.h"
@@ -78,6 +78,9 @@
using android::hardware::hidl_death_recipient;
using android::hidl::base::V1_0::IBase;
+using android::hardware::gnss::V1_0::GnssLocation;
+using android::hardware::gnss::V1_0::GnssLocationFlags;
+
using android::hardware::gnss::V1_0::IAGnss;
using android::hardware::gnss::V1_0::IAGnssCallback;
using android::hardware::gnss::V1_0::IAGnssCallback;
@@ -86,7 +89,6 @@
using android::hardware::gnss::V1_0::IGnss;
using android::hardware::gnss::V1_0::IGnssBatching;
using android::hardware::gnss::V1_0::IGnssBatchingCallback;
-using android::hardware::gnss::V1_0::IGnssCallback;
using android::hardware::gnss::V1_0::IGnssConfiguration;
using android::hardware::gnss::V1_0::IGnssDebug;
using android::hardware::gnss::V1_0::IGnssGeofenceCallback;
@@ -100,11 +102,14 @@
using android::hardware::gnss::V1_0::IGnssXtra;
using android::hardware::gnss::V1_0::IGnssXtraCallback;
+using IGnssV1_1 = android::hardware::gnss::V1_1::IGnss;
+using android::hardware::gnss::V1_1::IGnssCallback;
+
struct GnssDeathRecipient : virtual public hidl_death_recipient
{
// hidl_death_recipient interface
virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override {
- // TODO(gomo): implement a better death recovery mechanism without
+ // TODO(b/37460011): implement a better death recovery mechanism without
// crashing system server process as described in go//treble-gnss-death
LOG_ALWAYS_FATAL("Abort due to IGNSS hidl service failure,"
" restarting system server");
@@ -113,6 +118,7 @@
sp<GnssDeathRecipient> gnssHalDeathRecipient = nullptr;
sp<IGnss> gnssHal = nullptr;
+sp<IGnssV1_1> gnssHalV1_1 = nullptr;
sp<IGnssXtra> gnssXtraIface = nullptr;
sp<IAGnssRil> agnssRilIface = nullptr;
sp<IGnssGeofencing> gnssGeofencingIface = nullptr;
@@ -303,33 +309,33 @@
return env;
}
-static jobject translateLocation(JNIEnv* env, const hardware::gnss::V1_0::GnssLocation& location) {
+static jobject translateLocation(JNIEnv* env, const GnssLocation& location) {
JavaObject object(env, "android/location/Location", "gps");
uint16_t flags = static_cast<uint32_t>(location.gnssLocationFlags);
- if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_LAT_LONG) {
+ if (flags & GnssLocationFlags::HAS_LAT_LONG) {
SET(Latitude, location.latitudeDegrees);
SET(Longitude, location.longitudeDegrees);
}
- if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_ALTITUDE) {
+ if (flags & GnssLocationFlags::HAS_ALTITUDE) {
SET(Altitude, location.altitudeMeters);
}
- if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_SPEED) {
+ if (flags & GnssLocationFlags::HAS_SPEED) {
SET(Speed, location.speedMetersPerSec);
}
- if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_BEARING) {
+ if (flags & GnssLocationFlags::HAS_BEARING) {
SET(Bearing, location.bearingDegrees);
}
- if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_HORIZONTAL_ACCURACY) {
+ if (flags & GnssLocationFlags::HAS_HORIZONTAL_ACCURACY) {
SET(Accuracy, location.horizontalAccuracyMeters);
}
- if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
+ if (flags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
SET(VerticalAccuracyMeters, location.verticalAccuracyMeters);
}
- if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_SPEED_ACCURACY) {
+ if (flags & GnssLocationFlags::HAS_SPEED_ACCURACY) {
SET(SpeedAccuracyMetersPerSecond, location.speedAccuracyMetersPerSecond);
}
- if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_BEARING_ACCURACY) {
+ if (flags & GnssLocationFlags::HAS_BEARING_ACCURACY) {
SET(BearingAccuracyDegrees, location.bearingAccuracyDegrees);
}
SET(Time, location.timestamp);
@@ -341,8 +347,7 @@
* GnssCallback class implements the callback methods for IGnss interface.
*/
struct GnssCallback : public IGnssCallback {
- Return<void> gnssLocationCb(
- const android::hardware::gnss::V1_0::GnssLocation& location) override;
+ Return<void> gnssLocationCb(const GnssLocation& location) override;
Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue status) override;
Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override;
Return<void> gnssNmeaCb(int64_t timestamp, const android::hardware::hidl_string& nmea) override;
@@ -352,6 +357,9 @@
Return<void> gnssRequestTimeCb() override;
Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override;
+ // New in 1.1
+ Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
+
static GnssSvInfo sGnssSvList[static_cast<uint32_t>(
android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)];
static size_t sGnssSvListSize;
@@ -360,19 +368,30 @@
static size_t sNmeaStringLength;
};
+Return<void> GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
+ ALOGD("%s: name=%s\n", __func__, name.c_str());
+
+ // TODO(b/38003769): build Java code to connect to below code
+ /*
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_setGnssHardwareName, name);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ */
+ return Void();
+}
+
IGnssCallback::GnssSvInfo GnssCallback::sGnssSvList[static_cast<uint32_t>(
android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)];
const char* GnssCallback::sNmeaString = nullptr;
size_t GnssCallback::sNmeaStringLength = 0;
size_t GnssCallback::sGnssSvListSize = 0;
-Return<void> GnssCallback::gnssLocationCb(
- const ::android::hardware::gnss::V1_0::GnssLocation& location) {
+Return<void> GnssCallback::gnssLocationCb(const GnssLocation& location) {
JNIEnv* env = getJniEnv();
jobject jLocation = translateLocation(env, location);
bool hasLatLong = (static_cast<uint32_t>(location.gnssLocationFlags) &
- hardware::gnss::V1_0::GnssLocationFlags::HAS_LAT_LONG) != 0;
+ GnssLocationFlags::HAS_LAT_LONG) != 0;
env->CallVoidMethod(mCallbacksObj,
method_reportLocation,
@@ -484,12 +503,12 @@
// Methods from ::android::hardware::gps::V1_0::IGnssGeofenceCallback follow.
Return<void> gnssGeofenceTransitionCb(
int32_t geofenceId,
- const android::hardware::gnss::V1_0::GnssLocation& location,
+ const GnssLocation& location,
GeofenceTransition transition,
hardware::gnss::V1_0::GnssUtcTime timestamp) override;
Return<void> gnssGeofenceStatusCb(
GeofenceAvailability status,
- const android::hardware::gnss::V1_0::GnssLocation& location) override;
+ const GnssLocation& location) override;
Return<void> gnssGeofenceAddCb(int32_t geofenceId,
GeofenceStatus status) override;
Return<void> gnssGeofenceRemoveCb(int32_t geofenceId,
@@ -502,7 +521,7 @@
Return<void> GnssGeofenceCallback::gnssGeofenceTransitionCb(
int32_t geofenceId,
- const android::hardware::gnss::V1_0::GnssLocation& location,
+ const GnssLocation& location,
GeofenceTransition transition,
hardware::gnss::V1_0::GnssUtcTime timestamp) {
JNIEnv* env = getJniEnv();
@@ -522,7 +541,7 @@
Return<void> GnssGeofenceCallback::gnssGeofenceStatusCb(
GeofenceAvailability status,
- const android::hardware::gnss::V1_0::GnssLocation& location) {
+ const GnssLocation& location) {
JNIEnv* env = getJniEnv();
jobject jLocation = translateLocation(env, location);
@@ -976,12 +995,12 @@
* follow.
*/
Return<void> gnssLocationBatchCb(
- const ::android::hardware::hidl_vec<hardware::gnss::V1_0::GnssLocation> & locations)
+ const ::android::hardware::hidl_vec<GnssLocation> & locations)
override;
};
Return<void> GnssBatchingCallback::gnssLocationBatchCb(
- const ::android::hardware::hidl_vec<hardware::gnss::V1_0::GnssLocation> & locations) {
+ const ::android::hardware::hidl_vec<GnssLocation> & locations) {
JNIEnv* env = getJniEnv();
jobjectArray jLocations = env->NewObjectArray(locations.size(),
@@ -1049,8 +1068,13 @@
LOG_ALWAYS_FATAL("Unable to get Java VM. Error: %d", jvmStatus);
}
- // TODO(b/31632518)
- gnssHal = IGnss::getService();
+ gnssHal = gnssHalV1_1 = IGnssV1_1::getService();
+
+ if (gnssHal == nullptr) {
+ ALOGD("gnssHal 1.1 was null, trying 1.0");
+ gnssHal = IGnss::getService();
+ }
+
if (gnssHal != nullptr) {
gnssHalDeathRecipient = new GnssDeathRecipient();
hardware::Return<bool> linked = gnssHal->linkToDeath(
@@ -1160,7 +1184,6 @@
if (!mCallbacksObj)
mCallbacksObj = env->NewGlobalRef(obj);
- sp<IGnssCallback> gnssCbIface = new GnssCallback();
/*
* Fail if the main interface fails to initialize
*/
@@ -1169,7 +1192,14 @@
return JNI_FALSE;
}
- auto result = gnssHal->setCallback(gnssCbIface);
+ sp<IGnssCallback> gnssCbIface = new GnssCallback();
+
+ Return<bool> result = false;
+ if (gnssHalV1_1 != nullptr) {
+ result = gnssHalV1_1->setCallback_1_1(gnssCbIface);
+ } else {
+ result = gnssHal->setCallback(gnssCbIface);
+ }
if (!result.isOk() || !result) {
ALOGE("SetCallback for Gnss Interface fails\n");
return JNI_FALSE;
@@ -1182,7 +1212,7 @@
result = gnssXtraIface->setCallback(gnssXtraCbIface);
if (!result.isOk() || !result) {
gnssXtraIface = nullptr;
- ALOGE("SetCallback for Gnss Xtra Interface fails\n");
+ ALOGI("SetCallback for Gnss Xtra Interface fails\n");
}
}
@@ -1190,21 +1220,21 @@
if (agnssIface != nullptr) {
agnssIface->setCallback(aGnssCbIface);
} else {
- ALOGE("Unable to Initialize AGnss interface\n");
+ ALOGI("Unable to Initialize AGnss interface\n");
}
sp<IGnssGeofenceCallback> gnssGeofencingCbIface = new GnssGeofenceCallback();
if (gnssGeofencingIface != nullptr) {
gnssGeofencingIface->setCallback(gnssGeofencingCbIface);
} else {
- ALOGE("Unable to initialize GNSS Geofencing interface\n");
+ ALOGI("Unable to initialize GNSS Geofencing interface\n");
}
sp<IGnssNiCallback> gnssNiCbIface = new GnssNiCallback();
if (gnssNiIface != nullptr) {
gnssNiIface->setCallback(gnssNiCbIface);
} else {
- ALOGE("Unable to initialize GNSS NI interface\n");
+ ALOGI("Unable to initialize GNSS NI interface\n");
}
sp<IAGnssRilCallback> aGnssRilCbIface = new AGnssRilCallback();
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index b6c3df7..b2d35d4 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -41,10 +41,11 @@
using android::hardware::Return;
using android::hardware::Void;
-using android::hardware::power::V1_1::IPower;
using android::hardware::power::V1_0::PowerHint;
using android::hardware::power::V1_0::Feature;
using android::String8;
+using IPowerV1_1 = android::hardware::power::V1_1::IPower;
+using IPowerV1_0 = android::hardware::power::V1_0::IPower;
namespace android {
@@ -57,10 +58,11 @@
// ----------------------------------------------------------------------------
static jobject gPowerManagerServiceObj;
-sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0 = nullptr;
-sp<android::hardware::power::V1_1::IPower> gPowerHalV1_1 = nullptr;
-bool gPowerHalExists = true;
-std::mutex gPowerHalMutex;
+// Use getPowerHal* to retrieve a copy
+static sp<IPowerV1_0> gPowerHalV1_0_ = nullptr;
+static sp<IPowerV1_1> gPowerHalV1_1_ = nullptr;
+static bool gPowerHalExists = true;
+static std::mutex gPowerHalMutex;
static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];
// Throttling interval for user activity calls.
@@ -80,26 +82,63 @@
// Check validity of current handle to the power HAL service, and call getService() if necessary.
// The caller must be holding gPowerHalMutex.
-bool getPowerHal() {
- if (gPowerHalExists && gPowerHalV1_0 == nullptr) {
- gPowerHalV1_0 = android::hardware::power::V1_0::IPower::getService();
- if (gPowerHalV1_0 != nullptr) {
- gPowerHalV1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
- ALOGI("Loaded power HAL service");
+static void connectPowerHalLocked() {
+ if (gPowerHalExists && gPowerHalV1_0_ == nullptr) {
+ gPowerHalV1_0_ = IPowerV1_0::getService();
+ if (gPowerHalV1_0_ != nullptr) {
+ ALOGI("Loaded power HAL 1.0 service");
+ // Try cast to powerHAL V1_1
+ gPowerHalV1_1_ = IPowerV1_1::castFrom(gPowerHalV1_0_);
+ if (gPowerHalV1_1_ == nullptr) {
+ } else {
+ ALOGI("Loaded power HAL 1.1 service");
+ }
} else {
ALOGI("Couldn't load power HAL service");
gPowerHalExists = false;
}
}
- return gPowerHalV1_0 != nullptr;
+}
+
+// Retrieve a copy of PowerHAL V1_0
+sp<IPowerV1_0> getPowerHalV1_0() {
+ std::lock_guard<std::mutex> lock(gPowerHalMutex);
+ connectPowerHalLocked();
+ return gPowerHalV1_0_;
+}
+
+// Retrieve a copy of PowerHAL V1_1
+sp<IPowerV1_1> getPowerHalV1_1() {
+ std::lock_guard<std::mutex> lock(gPowerHalMutex);
+ connectPowerHalLocked();
+ return gPowerHalV1_1_;
}
// Check if a call to a power HAL function failed; if so, log the failure and invalidate the
-// current handle to the power HAL service. The caller must be holding gPowerHalMutex.
-static void processReturn(const Return<void> &ret, const char* functionName) {
+// current handle to the power HAL service.
+bool processPowerHalReturn(const Return<void> &ret, const char* functionName) {
if (!ret.isOk()) {
ALOGE("%s() failed: power HAL service not available.", functionName);
- gPowerHalV1_0 = nullptr;
+ gPowerHalMutex.lock();
+ gPowerHalV1_0_ = nullptr;
+ gPowerHalV1_1_ = nullptr;
+ gPowerHalMutex.unlock();
+ }
+ return ret.isOk();
+}
+
+static void sendPowerHint(PowerHint hintId, uint32_t data) {
+ sp<IPowerV1_1> powerHalV1_1 = getPowerHalV1_1();
+ Return<void> ret;
+ if (powerHalV1_1 != nullptr) {
+ ret = powerHalV1_1->powerHintAsync(hintId, data);
+ processPowerHalReturn(ret, "powerHintAsync");
+ } else {
+ sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
+ if (powerHalV1_0 != nullptr) {
+ ret = powerHalV1_0->powerHint(hintId, data);
+ processPowerHalReturn(ret, "powerHint");
+ }
}
}
@@ -119,20 +158,8 @@
}
gLastEventTime[eventType] = eventTime;
-
// Tell the power HAL when user activity occurs.
- gPowerHalMutex.lock();
- if (getPowerHal()) {
- Return<void> ret;
- if (gPowerHalV1_1 != nullptr) {
- ret = gPowerHalV1_1->powerHintAsync(PowerHint::INTERACTION, 0);
- } else {
- ret = gPowerHalV1_0->powerHint(PowerHint::INTERACTION, 0);
- }
- processReturn(ret, "powerHint");
- }
- gPowerHalMutex.unlock();
-
+ sendPowerHint(PowerHint::INTERACTION, 0);
}
JNIEnv* env = AndroidRuntime::getJNIEnv();
@@ -150,7 +177,7 @@
gPowerManagerServiceObj = env->NewGlobalRef(obj);
gPowerHalMutex.lock();
- getPowerHal();
+ connectPowerHalLocked();
gPowerHalMutex.unlock();
}
@@ -165,11 +192,11 @@
}
static void nativeSetInteractive(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {
- std::lock_guard<std::mutex> lock(gPowerHalMutex);
- if (getPowerHal()) {
+ sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
+ if (powerHalV1_0 != nullptr) {
android::base::Timer t;
- Return<void> ret = gPowerHalV1_0->setInteractive(enable);
- processReturn(ret, "setInteractive");
+ Return<void> ret = powerHalV1_0->setInteractive(enable);
+ processPowerHalReturn(ret, "setInteractive");
if (t.duration() > 20ms) {
ALOGD("Excessive delay in setInteractive(%s) while turning screen %s",
enable ? "true" : "false", enable ? "on" : "off");
@@ -193,24 +220,15 @@
}
}
-static void nativeSendPowerHint(JNIEnv *env, jclass clazz, jint hintId, jint data) {
- std::lock_guard<std::mutex> lock(gPowerHalMutex);
- if (getPowerHal()) {
- Return<void> ret;
- if (gPowerHalV1_1 != nullptr) {
- ret = gPowerHalV1_1->powerHintAsync((PowerHint)hintId, data);
- } else {
- ret = gPowerHalV1_0->powerHint((PowerHint)hintId, data);
- }
- processReturn(ret, "powerHint");
- }
+static void nativeSendPowerHint(JNIEnv* /* env */, jclass /* clazz */, jint hintId, jint data) {
+ sendPowerHint(static_cast<PowerHint>(hintId), data);
}
-static void nativeSetFeature(JNIEnv *env, jclass clazz, jint featureId, jint data) {
- std::lock_guard<std::mutex> lock(gPowerHalMutex);
- if (getPowerHal()) {
- Return<void> ret = gPowerHalV1_0->setFeature((Feature)featureId, static_cast<bool>(data));
- processReturn(ret, "setFeature");
+static void nativeSetFeature(JNIEnv* /* env */, jclass /* clazz */, jint featureId, jint data) {
+ sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
+ if (powerHalV1_0 != nullptr) {
+ Return<void> ret = powerHalV1_0->setFeature((Feature)featureId, static_cast<bool>(data));
+ processPowerHalReturn(ret, "setFeature");
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
new file mode 100644
index 0000000..84cfabe
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -0,0 +1,60 @@
+/*
+ * 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.devicepolicy;
+
+import android.app.admin.IDevicePolicyManager;
+import android.content.ComponentName;
+
+import com.android.internal.R;
+import com.android.server.SystemService;
+
+/**
+ * Defines the required interface for IDevicePolicyManager implemenation.
+ *
+ * <p>The interface consists of public parts determined by {@link IDevicePolicyManager} and also
+ * several package private methods required by internal infrastructure.
+ *
+ * <p>Whenever adding an AIDL method to {@link IDevicePolicyManager}, an empty override method
+ * should be added here to avoid build breakage in downstream branches.
+ */
+abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
+ /**
+ * To be called by {@link DevicePolicyManagerService#Lifecycle} during the various boot phases.
+ *
+ * @see {@link SystemService#onBootPhase}.
+ */
+ abstract void systemReady(int phase);
+ /**
+ * To be called by {@link DevicePolicyManagerService#Lifecycle} when a new user starts.
+ *
+ * @see {@link SystemService#onStartUser}
+ */
+ abstract void handleStartUser(int userId);
+ /**
+ * To be called by {@link DevicePolicyManagerService#Lifecycle} when a user is being unlocked.
+ *
+ * @see {@link SystemService#onUnlockUser}
+ */
+ abstract void handleUnlockUser(int userId);
+ /**
+ * To be called by {@link DevicePolicyManagerService#Lifecycle} when a user is being stopped.
+ *
+ * @see {@link SystemService#onStopUser}
+ */
+ abstract void handleStopUser(int userId);
+
+ public void setSystemSetting(ComponentName who, String setting, String value){}
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 60c36d1..b979ff4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -19,6 +19,7 @@
import static android.Manifest.permission.BIND_DEVICE_ADMIN;
import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
+import static android.app.ActivityManager.USER_OP_SUCCESS;
import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY;
import static android.app.admin.DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED;
import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE;
@@ -150,6 +151,9 @@
import android.security.IKeyChainService;
import android.security.KeyChain;
import android.security.KeyChain.KeyChainConnection;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.ParcelableKeyGenParameterSpec;
+import android.security.KeyStore;
import android.service.persistentdata.PersistentDataBlockManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -198,6 +202,8 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
+import java.lang.IllegalStateException;
+import java.lang.reflect.Constructor;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.util.ArrayList;
@@ -214,7 +220,7 @@
/**
* Implementation of the device policy APIs.
*/
-public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
+public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
protected static final String LOG_TAG = "DevicePolicyManager";
@@ -313,6 +319,7 @@
private static final Set<String> SECURE_SETTINGS_DEVICEOWNER_WHITELIST;
private static final Set<String> GLOBAL_SETTINGS_WHITELIST;
private static final Set<String> GLOBAL_SETTINGS_DEPRECATED;
+ private static final Set<String> SYSTEM_SETTINGS_WHITELIST;
static {
SECURE_SETTINGS_WHITELIST = new ArraySet<>();
SECURE_SETTINGS_WHITELIST.add(Settings.Secure.DEFAULT_INPUT_METHOD);
@@ -339,6 +346,11 @@
GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.MODE_RINGER);
GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.NETWORK_PREFERENCE);
GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.WIFI_ON);
+
+ SYSTEM_SETTINGS_WHITELIST = new ArraySet<>();
+ SYSTEM_SETTINGS_WHITELIST.add(Settings.System.SCREEN_BRIGHTNESS);
+ SYSTEM_SETTINGS_WHITELIST.add(Settings.System.SCREEN_BRIGHTNESS_MODE);
+ SYSTEM_SETTINGS_WHITELIST.add(Settings.System.SCREEN_OFF_TIMEOUT);
}
/**
@@ -451,11 +463,24 @@
};
public static final class Lifecycle extends SystemService {
- private DevicePolicyManagerService mService;
+ private BaseIDevicePolicyManager mService;
public Lifecycle(Context context) {
super(context);
- mService = new DevicePolicyManagerService(context);
+ String dpmsClassName = context.getResources()
+ .getString(R.string.config_deviceSpecificDevicePolicyManagerService);
+ if (TextUtils.isEmpty(dpmsClassName)) {
+ dpmsClassName = DevicePolicyManagerService.class.getName();
+ }
+ try {
+ Class serviceClass = Class.forName(dpmsClassName);
+ Constructor constructor = serviceClass.getConstructor(Context.class);
+ mService = (BaseIDevicePolicyManager) constructor.newInstance(context);
+ } catch (Exception e) {
+ throw new IllegalStateException(
+ "Failed to instantiate DevicePolicyManagerService with class name: "
+ + dpmsClassName, e);
+ }
}
@Override
@@ -715,6 +740,7 @@
private static final String TAG_ORGANIZATION_NAME = "organization-name";
private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification";
private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
+ private static final String TAG_IS_LOGOUT_BUTTON_ENABLED = "is_logout_button_enabled";
final DeviceAdminInfo info;
@@ -764,6 +790,7 @@
boolean requireAutoTime = false; // Can only be set by a device owner.
boolean forceEphemeralUsers = false; // Can only be set by a device owner.
boolean isNetworkLoggingEnabled = false; // Can only be set by a device owner.
+ boolean isLogoutButtonEnabled = false; // Can only be set by a device owner.
// one notification after enabling + one more after reboots
static final int DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN = 2;
@@ -1081,6 +1108,11 @@
out.text(organizationName);
out.endTag(null, TAG_ORGANIZATION_NAME);
}
+ if (isLogoutButtonEnabled) {
+ out.startTag(null, TAG_IS_LOGOUT_BUTTON_ENABLED);
+ out.attribute(null, ATTR_VALUE, Boolean.toString(isLogoutButtonEnabled));
+ out.endTag(null, TAG_IS_LOGOUT_BUTTON_ENABLED);
+ }
}
void writePackageListToXml(XmlSerializer out, String outerTag,
@@ -1254,6 +1286,9 @@
} else {
Log.w(LOG_TAG, "Missing text when loading organization name");
}
+ } else if (TAG_IS_LOGOUT_BUTTON_ENABLED.equals(tag)) {
+ isLogoutButtonEnabled = Boolean.parseBoolean(
+ parser.getAttributeValue(null, ATTR_VALUE));
} else {
Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -1551,6 +1586,10 @@
mContext = context;
}
+ public boolean hasFeature() {
+ return getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
+ }
+
Context createContextAsUser(UserHandle user) throws PackageManager.NameNotFoundException {
final String packageName = mContext.getPackageName();
return mContext.createPackageContextAsUser(packageName, 0, user);
@@ -1803,6 +1842,10 @@
Settings.Global.putString(mContext.getContentResolver(), name, value);
}
+ void settingsSystemPutString(String name, String value) {
+ Settings.System.putString(mContext.getContentResolver(), name, value);
+ }
+
void securityLogSetLoggingEnabledProperty(boolean enabled) {
SecurityLog.setLoggingEnabledProperty(enabled);
}
@@ -1848,8 +1891,7 @@
// TODO: why does SecurityLogMonitor need to be created even when mHasFeature == false?
mSecurityLogMonitor = new SecurityLogMonitor(this);
- mHasFeature = mInjector.getPackageManager()
- .hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
+ mHasFeature = mInjector.hasFeature();
mIsWatch = mInjector.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_WATCH);
mBackgroundHandler = BackgroundThread.getHandler();
@@ -3033,6 +3075,7 @@
}
@VisibleForTesting
+ @Override
void systemReady(int phase) {
if (!mHasFeature) {
return;
@@ -3099,6 +3142,7 @@
}
}
+ @Override
void handleStartUser(int userId) {
updateScreenCaptureDisabledInWindowManager(userId,
getScreenCaptureDisabled(null, userId));
@@ -3107,10 +3151,12 @@
startOwnerService(userId, "start-user");
}
+ @Override
void handleUnlockUser(int userId) {
startOwnerService(userId, "unlock-user");
}
+ @Override
void handleStopUser(int userId) {
stopOwnerService(userId, "stop-user");
}
@@ -4979,6 +5025,54 @@
}
@Override
+ public boolean generateKeyPair(ComponentName who, String callerPackage, String algorithm,
+ ParcelableKeyGenParameterSpec parcelableKeySpec) {
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_CERT_INSTALL);
+ final KeyGenParameterSpec keySpec = parcelableKeySpec.getSpec();
+ if (TextUtils.isEmpty(keySpec.getKeystoreAlias())) {
+ throw new IllegalArgumentException("Empty alias provided.");
+ }
+ // As the caller will be granted access to the key, ensure no UID was specified, as
+ // it will not have the desired effect.
+ if (keySpec.getUid() != KeyStore.UID_SELF) {
+ Log.e(LOG_TAG, "Only the caller can be granted access to the generated keypair.");
+ return false;
+ }
+ final int callingUid = mInjector.binderGetCallingUid();
+
+ final UserHandle userHandle = mInjector.binderGetCallingUserHandle();
+ final long id = mInjector.binderClearCallingIdentity();
+ try {
+ try (KeyChainConnection keyChainConnection =
+ KeyChain.bindAsUser(mContext, userHandle)) {
+ IKeyChainService keyChain = keyChainConnection.getService();
+ final boolean generationResult = keyChain.generateKeyPair(algorithm, parcelableKeySpec);
+ if (!generationResult) {
+ Log.e(LOG_TAG, "KeyChain failed to generate a keypair.");
+ return false;
+ }
+
+ // Set a grant for the caller here so that when the client calls
+ // requestPrivateKey, it will be able to get the key from Keystore.
+ // Note the use of the calling UID, since the request for the private
+ // key will come from the client's process, so the grant has to be for
+ // that UID.
+ keyChain.setGrant(callingUid, keySpec.getKeystoreAlias(), true);
+ return true;
+ }
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "KeyChain error while generating a keypair", e);
+ } catch (InterruptedException e) {
+ Log.w(LOG_TAG, "Interrupted while generating keypair", e);
+ Thread.currentThread().interrupt();
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
+ }
+ return false;
+ }
+
+ @Override
public void choosePrivateKeyAlias(final int uid, final Uri uri, final String alias,
final IBinder response) {
// Caller UID needs to be trusted, so we restrict this method to SYSTEM_UID callers.
@@ -6943,8 +7037,13 @@
return;
}
+ final int userId = mInjector.userHandleGetCallingUserId();
synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (!isUserAffiliatedWithDeviceLocked(userId)) {
+ throw new SecurityException("Admin " + who +
+ " is neither the device owner or affiliated user's profile owner.");
+ }
long token = mInjector.binderClearCallingIdentity();
try {
mLockPatternUtils.setDeviceOwnerInfo(info != null ? info.toString() : null);
@@ -8356,6 +8455,90 @@
}
@Override
+ public boolean stopUser(ComponentName who, UserHandle userHandle) {
+ Preconditions.checkNotNull(who, "ComponentName is null");
+
+ synchronized (this) {
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ }
+
+ final int userId = userHandle.getIdentifier();
+ if (isManagedProfile(userId)) {
+ Log.w(LOG_TAG, "Managed profile cannot be stopped");
+ return false;
+ }
+
+ final long id = mInjector.binderClearCallingIdentity();
+ try {
+ return mInjector.getIActivityManager().stopUser(userId, true /*force*/, null)
+ == USER_OP_SUCCESS;
+ } catch (RemoteException e) {
+ // Same process, should not happen.
+ return false;
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
+ }
+ }
+
+ @Override
+ public boolean logoutUser(ComponentName who) {
+ Preconditions.checkNotNull(who, "ComponentName is null");
+
+ final int callingUserId = mInjector.userHandleGetCallingUserId();
+ synchronized (this) {
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (!isUserAffiliatedWithDeviceLocked(callingUserId)) {
+ throw new SecurityException("Admin " + who +
+ " is neither the device owner or affiliated user's profile owner.");
+ }
+ }
+
+ if (isManagedProfile(callingUserId)) {
+ Log.w(LOG_TAG, "Managed profile cannot be logout");
+ return false;
+ }
+
+ final long id = mInjector.binderClearCallingIdentity();
+ try {
+ if (!mInjector.getIActivityManager().switchUser(UserHandle.USER_SYSTEM)) {
+ Log.w(LOG_TAG, "Failed to switch to primary user");
+ return false;
+ }
+ return mInjector.getIActivityManager().stopUser(callingUserId, true /*force*/, null)
+ == USER_OP_SUCCESS;
+ } catch (RemoteException e) {
+ // Same process, should not happen.
+ return false;
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
+ }
+ }
+
+ @Override
+ public List<UserHandle> getSecondaryUsers(ComponentName who) {
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ synchronized (this) {
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ }
+
+ final long id = mInjector.binderClearCallingIdentity();
+ try {
+ final List<UserInfo> userInfos = mInjector.getUserManager().getUsers(true
+ /*excludeDying*/);
+ final List<UserHandle> userHandles = new ArrayList<>();
+ for (UserInfo userInfo : userInfos) {
+ UserHandle userHandle = userInfo.getUserHandle();
+ if (!userHandle.isSystem() && !isManagedProfile(userHandle.getIdentifier())) {
+ userHandles.add(userInfo.getUserHandle());
+ }
+ }
+ return userHandles;
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
+ }
+ }
+
+ @Override
public Bundle getApplicationRestrictions(ComponentName who, String callerPackage,
String packageName) {
enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
@@ -9110,6 +9293,24 @@
}
@Override
+ public void setSystemSetting(ComponentName who, String setting, String value) {
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ Preconditions.checkStringNotEmpty(setting, "String setting is null or empty");
+
+ synchronized (this) {
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+
+ if (!SYSTEM_SETTINGS_WHITELIST.contains(setting)) {
+ throw new SecurityException(String.format(
+ "Permission denial: device owners cannot update %1$s", setting));
+ }
+
+ mInjector.binderWithCleanCallingIdentity(() -> mInjector.settingsSystemPutString(
+ setting, value));
+ }
+ }
+
+ @Override
public boolean setTime(ComponentName who, long millis) {
Preconditions.checkNotNull(who, "ComponentName is null in setTime");
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
@@ -9236,10 +9437,14 @@
@Override
public boolean setKeyguardDisabled(ComponentName who, boolean disabled) {
Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userId = mInjector.userHandleGetCallingUserId();
synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (!isUserAffiliatedWithDeviceLocked(userId)) {
+ throw new SecurityException("Admin " + who +
+ " is neither the device owner or affiliated user's profile owner.");
+ }
}
- final int userId = UserHandle.getCallingUserId();
long ident = mInjector.binderClearCallingIdentity();
try {
@@ -9261,7 +9466,11 @@
public boolean setStatusBarDisabled(ComponentName who, boolean disabled) {
int userId = UserHandle.getCallingUserId();
synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (!isUserAffiliatedWithDeviceLocked(userId)) {
+ throw new SecurityException("Admin " + who +
+ " is neither the device owner or affiliated user's profile owner.");
+ }
DevicePolicyData policy = getUserData(userId);
if (policy.mStatusBarDisabled != disabled) {
boolean isLockTaskMode = false;
@@ -9526,6 +9735,11 @@
}
return null;
}
+
+ @Override
+ public boolean isUserAffiliatedWithDevice(int userId) {
+ return DevicePolicyManagerService.this.isUserAffiliatedWithDeviceLocked(userId);
+ }
}
private Intent createShowAdminSupportIntent(ComponentName admin, int userId) {
@@ -11365,4 +11579,37 @@
}
return false;
}
+
+ @Override
+ public synchronized void setLogoutButtonEnabled(ComponentName admin, boolean enabled) {
+ if (!mHasFeature) {
+ return;
+ }
+ Preconditions.checkNotNull(admin);
+ getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+
+ if (enabled == isLogoutButtonEnabledInternalLocked()) {
+ // already in the requested state
+ return;
+ }
+ ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
+ deviceOwner.isLogoutButtonEnabled = enabled;
+ saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ }
+
+ @Override
+ public boolean isLogoutButtonEnabled() {
+ if (!mHasFeature) {
+ return false;
+ }
+ synchronized (this) {
+ return isLogoutButtonEnabledInternalLocked();
+ }
+ }
+
+ private boolean isLogoutButtonEnabledInternalLocked() {
+ ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
+ return (deviceOwner != null) && deviceOwner.isLogoutButtonEnabled;
+ }
+
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
index 6086354..4a6bee5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
@@ -64,6 +64,8 @@
private final DevicePolicyManagerService mDpm;
private final AlarmManager mAlarmManager;
+ private long mId;
+
private final OnAlarmListener mBatchTimeoutAlarmListener = new OnAlarmListener() {
@Override
public void onAlarm() {
@@ -185,6 +187,10 @@
private Bundle finalizeBatchAndBuildDeviceOwnerMessageLocked() {
Bundle notificationExtras = null;
if (mNetworkEvents.size() > 0) {
+ // Assign ids to the events.
+ for (NetworkEvent event : mNetworkEvents) {
+ event.setId(mId++);
+ }
// Finalize the batch and start a new one from scratch.
if (mBatches.size() >= MAX_BATCHES) {
// Remove the oldest batch if we hit the limit.
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 33f4e34..4c994b9 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -215,6 +215,9 @@
"com.android.server.timezone.RulesManagerService$Lifecycle";
private static final String IOT_SERVICE_CLASS =
"com.google.android.things.services.IoTSystemService";
+ private static final String SLICE_MANAGER_SERVICE_CLASS =
+ "com.android.server.slice.SliceManagerService$Lifecycle";
+
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file";
@@ -730,6 +733,7 @@
boolean disableVrManager = SystemProperties.getBoolean("config.disable_vrmanager", false);
boolean disableCameraService = SystemProperties.getBoolean("config.disable_cameraservice",
false);
+ boolean disableSlices = SystemProperties.getBoolean("config.disable_slices", false);
boolean enableLeftyService = SystemProperties.getBoolean("config.enable_lefty", false);
boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
@@ -1523,6 +1527,12 @@
}
}
+ if (!disableSlices) {
+ traceBeginAndSlog("StartSliceManagerService");
+ mSystemServiceManager.startService(SLICE_MANAGER_SERVICE_CLASS);
+ traceEnd();
+ }
+
if (!disableCameraService) {
traceBeginAndSlog("StartCameraServiceProxy");
mSystemServiceManager.startService(CameraServiceProxy.class);
diff --git a/services/net/java/android/net/ip/ConnectivityPacketTracker.java b/services/net/java/android/net/ip/ConnectivityPacketTracker.java
index 1925c39..6cf4fa9a 100644
--- a/services/net/java/android/net/ip/ConnectivityPacketTracker.java
+++ b/services/net/java/android/net/ip/ConnectivityPacketTracker.java
@@ -19,7 +19,7 @@
import static android.system.OsConstants.*;
import android.net.NetworkUtils;
-import android.net.util.BlockingSocketReader;
+import android.net.util.PacketReader;
import android.net.util.ConnectivityPacketSummary;
import android.os.Handler;
import android.system.ErrnoException;
@@ -65,7 +65,7 @@
private final String mTag;
private final LocalLog mLog;
- private final BlockingSocketReader mPacketListener;
+ private final PacketReader mPacketListener;
private boolean mRunning;
private String mDisplayName;
@@ -101,7 +101,7 @@
mDisplayName = null;
}
- private final class PacketListener extends BlockingSocketReader {
+ private final class PacketListener extends PacketReader {
private final int mIfIndex;
private final byte mHwAddr[];
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index 70983c8..b305b33 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -163,10 +163,10 @@
// TODO: Find an lighter weight approach.
private class LoggingCallbackWrapper extends Callback {
private static final String PREFIX = "INVOKE ";
- private Callback mCallback;
+ private final Callback mCallback;
public LoggingCallbackWrapper(Callback callback) {
- mCallback = callback;
+ mCallback = (callback != null) ? callback : new Callback();
}
private void log(String msg) {
@@ -815,6 +815,15 @@
pw.println(Objects.toString(provisioningConfig, "N/A"));
pw.decreaseIndent();
+ final IpReachabilityMonitor iprm = mIpReachabilityMonitor;
+ if (iprm != null) {
+ pw.println();
+ pw.println(mTag + " current IpReachabilityMonitor state:");
+ pw.increaseIndent();
+ iprm.dump(pw);
+ pw.decreaseIndent();
+ }
+
pw.println();
pw.println(mTag + " StateMachine dump:");
pw.increaseIndent();
@@ -1237,6 +1246,7 @@
mIpReachabilityMonitor = new IpReachabilityMonitor(
mContext,
mInterfaceName,
+ getHandler(),
mLog,
new IpReachabilityMonitor.Callback() {
@Override
@@ -1273,6 +1283,7 @@
stopAllIP();
resetLinkProperties();
+ mCallback.onLinkPropertiesChange(new LinkProperties(mLinkProperties));
if (mStartTimeMillis > 0) {
recordMetric(IpManagerEvent.COMPLETE_LIFECYCLE);
mStartTimeMillis = 0;
diff --git a/services/net/java/android/net/ip/IpNeighborMonitor.java b/services/net/java/android/net/ip/IpNeighborMonitor.java
new file mode 100644
index 0000000..6807334
--- /dev/null
+++ b/services/net/java/android/net/ip/IpNeighborMonitor.java
@@ -0,0 +1,236 @@
+/*
+ * 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 android.net.ip;
+
+import android.net.netlink.NetlinkConstants;
+import android.net.netlink.NetlinkErrorMessage;
+import android.net.netlink.NetlinkMessage;
+import android.net.netlink.NetlinkSocket;
+import android.net.netlink.RtNetlinkNeighborMessage;
+import android.net.netlink.StructNdMsg;
+import android.net.netlink.StructNlMsgHdr;
+import android.net.util.PacketReader;
+import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.system.ErrnoException;
+import android.system.NetlinkSocketAddress;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.Log;
+
+import com.android.internal.util.BitUtils;
+
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+
+import java.io.FileDescriptor;
+import java.net.InetAddress;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.StringJoiner;
+
+
+/**
+ * IpNeighborMonitor.
+ *
+ * Monitors the kernel rtnetlink neighbor notifications and presents to callers
+ * NeighborEvents describing each event. Callers can provide a consumer instance
+ * to both filter (e.g. by interface index and IP address) and handle the
+ * generated NeighborEvents.
+ *
+ * @hide
+ */
+public class IpNeighborMonitor extends PacketReader {
+ private static final String TAG = IpNeighborMonitor.class.getSimpleName();
+ private static final boolean DBG = false;
+ private static final boolean VDBG = false;
+
+ /**
+ * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
+ * for the given IP address on the specified interface index.
+ *
+ * @return 0 if the request was successfully passed to the kernel; otherwise return
+ * a non-zero error code.
+ */
+ public static int startKernelNeighborProbe(int ifIndex, InetAddress ip) {
+ final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex;
+ if (DBG) { Log.d(TAG, msgSnippet); }
+
+ final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
+ 1, ip, StructNdMsg.NUD_PROBE, ifIndex, null);
+
+ try {
+ NetlinkSocket.sendOneShotKernelMessage(OsConstants.NETLINK_ROUTE, msg);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Error " + msgSnippet + ": " + e);
+ return -e.errno;
+ }
+
+ return 0;
+ }
+
+ public static class NeighborEvent {
+ final long elapsedMs;
+ final short msgType;
+ final int ifindex;
+ final InetAddress ip;
+ final short nudState;
+ final byte[] linkLayerAddr;
+
+ public NeighborEvent(long elapsedMs, short msgType, int ifindex, InetAddress ip,
+ short nudState, byte[] linkLayerAddr) {
+ this.elapsedMs = elapsedMs;
+ this.msgType = msgType;
+ this.ifindex = ifindex;
+ this.ip = ip;
+ this.nudState = nudState;
+ this.linkLayerAddr = linkLayerAddr;
+ }
+
+ boolean isConnected() {
+ return (msgType != NetlinkConstants.RTM_DELNEIGH) &&
+ StructNdMsg.isNudStateConnected(nudState);
+ }
+
+ boolean isValid() {
+ return (msgType != NetlinkConstants.RTM_DELNEIGH) &&
+ StructNdMsg.isNudStateValid(nudState);
+ }
+
+ @Override
+ public String toString() {
+ final StringJoiner j = new StringJoiner(",", "NeighborEvent{", "}");
+ return j.add("@" + elapsedMs)
+ .add(NetlinkConstants.stringForNlMsgType(msgType))
+ .add("if=" + ifindex)
+ .add(ip.getHostAddress())
+ .add(StructNdMsg.stringForNudState(nudState))
+ .add("[" + NetlinkConstants.hexify(linkLayerAddr) + "]")
+ .toString();
+ }
+ }
+
+ public interface NeighborEventConsumer {
+ // Every neighbor event received on the netlink socket is passed in
+ // here. Subclasses should filter for events of interest.
+ public void accept(NeighborEvent event);
+ }
+
+ private final SharedLog mLog;
+ private final NeighborEventConsumer mConsumer;
+
+ public IpNeighborMonitor(Handler h, SharedLog log, NeighborEventConsumer cb) {
+ super(h, NetlinkSocket.DEFAULT_RECV_BUFSIZE);
+ mLog = log.forSubComponent(TAG);
+ mConsumer = (cb != null) ? cb : (event) -> { /* discard */ };
+ }
+
+ @Override
+ protected FileDescriptor createFd() {
+ FileDescriptor fd = null;
+
+ try {
+ fd = NetlinkSocket.forProto(OsConstants.NETLINK_ROUTE);
+ Os.bind(fd, (SocketAddress)(new NetlinkSocketAddress(0, OsConstants.RTMGRP_NEIGH)));
+ Os.connect(fd, (SocketAddress)(new NetlinkSocketAddress(0, 0)));
+
+ if (VDBG) {
+ final NetlinkSocketAddress nlAddr = (NetlinkSocketAddress) Os.getsockname(fd);
+ Log.d(TAG, "bound to sockaddr_nl{"
+ + BitUtils.uint32(nlAddr.getPortId()) + ", "
+ + nlAddr.getGroupsMask()
+ + "}");
+ }
+ } catch (ErrnoException|SocketException e) {
+ logError("Failed to create rtnetlink socket", e);
+ IoUtils.closeQuietly(fd);
+ return null;
+ }
+
+ return fd;
+ }
+
+ @Override
+ protected void handlePacket(byte[] recvbuf, int length) {
+ final long whenMs = SystemClock.elapsedRealtime();
+
+ final ByteBuffer byteBuffer = ByteBuffer.wrap(recvbuf, 0, length);
+ byteBuffer.order(ByteOrder.nativeOrder());
+
+ parseNetlinkMessageBuffer(byteBuffer, whenMs);
+ }
+
+ private void parseNetlinkMessageBuffer(ByteBuffer byteBuffer, long whenMs) {
+ while (byteBuffer.remaining() > 0) {
+ final int position = byteBuffer.position();
+ final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer);
+ if (nlMsg == null || nlMsg.getHeader() == null) {
+ byteBuffer.position(position);
+ mLog.e("unparsable netlink msg: " + NetlinkConstants.hexify(byteBuffer));
+ break;
+ }
+
+ final int srcPortId = nlMsg.getHeader().nlmsg_pid;
+ if (srcPortId != 0) {
+ mLog.e("non-kernel source portId: " + BitUtils.uint32(srcPortId));
+ break;
+ }
+
+ if (nlMsg instanceof NetlinkErrorMessage) {
+ mLog.e("netlink error: " + nlMsg);
+ continue;
+ } else if (!(nlMsg instanceof RtNetlinkNeighborMessage)) {
+ mLog.i("non-rtnetlink neighbor msg: " + nlMsg);
+ continue;
+ }
+
+ evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs);
+ }
+ }
+
+ private void evaluateRtNetlinkNeighborMessage(
+ RtNetlinkNeighborMessage neighMsg, long whenMs) {
+ final short msgType = neighMsg.getHeader().nlmsg_type;
+ final StructNdMsg ndMsg = neighMsg.getNdHeader();
+ if (ndMsg == null) {
+ mLog.e("RtNetlinkNeighborMessage without ND message header!");
+ return;
+ }
+
+ final int ifindex = ndMsg.ndm_ifindex;
+ final InetAddress destination = neighMsg.getDestination();
+ final short nudState =
+ (msgType == NetlinkConstants.RTM_DELNEIGH)
+ ? StructNdMsg.NUD_NONE
+ : ndMsg.ndm_state;
+
+ final NeighborEvent event = new NeighborEvent(
+ whenMs, msgType, ifindex, destination, nudState, neighMsg.getLinkLayerAddress());
+
+ if (VDBG) {
+ Log.d(TAG, neighMsg.toString());
+ }
+ if (DBG) {
+ Log.d(TAG, event.toString());
+ }
+
+ mConsumer.accept(event);
+ }
+}
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index 714b35a..b31ffbb 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -22,30 +22,27 @@
import android.net.LinkProperties.ProvisioningChange;
import android.net.ProxyInfo;
import android.net.RouteInfo;
+import android.net.ip.IpNeighborMonitor.NeighborEvent;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.IpReachabilityEvent;
-import android.net.netlink.NetlinkConstants;
-import android.net.netlink.NetlinkErrorMessage;
-import android.net.netlink.NetlinkMessage;
-import android.net.netlink.NetlinkSocket;
-import android.net.netlink.RtNetlinkNeighborMessage;
import android.net.netlink.StructNdMsg;
-import android.net.netlink.StructNdaCacheInfo;
-import android.net.netlink.StructNlMsgHdr;
import android.net.util.MultinetworkPolicyTracker;
import android.net.util.SharedLog;
+import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.SystemClock;
import android.system.ErrnoException;
-import android.system.NetlinkSocketAddress;
import android.system.OsConstants;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.DumpUtils.Dump;
import java.io.InterruptedIOException;
+import java.io.PrintWriter;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@@ -134,6 +131,8 @@
* state it may be best for the link to disconnect completely and
* reconnect afresh.
*
+ * Accessing an instance of this class from multiple threads is NOT safe.
+ *
* @hide
*/
public class IpReachabilityMonitor {
@@ -169,64 +168,33 @@
}
}
- private final Object mLock = new Object();
private final String mInterfaceName;
private final int mInterfaceIndex;
+ private final IpNeighborMonitor mIpNeighborMonitor;
private final SharedLog mLog;
private final Callback mCallback;
private final Dependencies mDependencies;
private final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
- private final NetlinkSocketObserver mNetlinkSocketObserver;
- private final Thread mObserverThread;
private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
- @GuardedBy("mLock")
private LinkProperties mLinkProperties = new LinkProperties();
- // TODO: consider a map to a private NeighborState class holding more
- // information than a single NUD state entry.
- @GuardedBy("mLock")
- private Map<InetAddress, Short> mIpWatchList = new HashMap<>();
- @GuardedBy("mLock")
- private int mIpWatchListVersion;
- private volatile boolean mRunning;
+ private Map<InetAddress, NeighborEvent> mNeighborWatchList = new HashMap<>();
// Time in milliseconds of the last forced probe request.
private volatile long mLastProbeTimeMs;
- /**
- * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
- * for the given IP address on the specified interface index.
- *
- * @return 0 if the request was successfully passed to the kernel; otherwise return
- * a non-zero error code.
- */
- private static int probeNeighbor(int ifIndex, InetAddress ip) {
- final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex;
- if (DBG) { Log.d(TAG, msgSnippet); }
-
- final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
- 1, ip, StructNdMsg.NUD_PROBE, ifIndex, null);
-
- try {
- NetlinkSocket.sendOneShotKernelMessage(OsConstants.NETLINK_ROUTE, msg);
- } catch (ErrnoException e) {
- Log.e(TAG, "Error " + msgSnippet + ": " + e);
- return -e.errno;
- }
-
- return 0;
+ public IpReachabilityMonitor(
+ Context context, String ifName, Handler h, SharedLog log, Callback callback) {
+ this(context, ifName, h, log, callback, null);
}
- public IpReachabilityMonitor(Context context, String ifName, SharedLog log, Callback callback) {
- this(context, ifName, log, callback, null);
- }
-
- public IpReachabilityMonitor(Context context, String ifName, SharedLog log, Callback callback,
+ public IpReachabilityMonitor(
+ Context context, String ifName, Handler h, SharedLog log, Callback callback,
MultinetworkPolicyTracker tracker) {
- this(ifName, getInterfaceIndex(ifName), log, callback, tracker,
+ this(ifName, getInterfaceIndex(ifName), h, log, callback, tracker,
Dependencies.makeDefault(context, ifName));
}
@VisibleForTesting
- IpReachabilityMonitor(String ifName, int ifIndex, SharedLog log, Callback callback,
+ IpReachabilityMonitor(String ifName, int ifIndex, Handler h, SharedLog log, Callback callback,
MultinetworkPolicyTracker tracker, Dependencies dependencies) {
mInterfaceName = ifName;
mLog = log.forSubComponent(TAG);
@@ -234,47 +202,56 @@
mMultinetworkPolicyTracker = tracker;
mInterfaceIndex = ifIndex;
mDependencies = dependencies;
- mNetlinkSocketObserver = new NetlinkSocketObserver();
- mObserverThread = new Thread(mNetlinkSocketObserver);
- mObserverThread.start();
+
+ mIpNeighborMonitor = new IpNeighborMonitor(h, mLog,
+ (NeighborEvent event) -> {
+ if (mInterfaceIndex != event.ifindex) return;
+ if (!mNeighborWatchList.containsKey(event.ip)) return;
+
+ final NeighborEvent prev = mNeighborWatchList.put(event.ip, event);
+
+ // TODO: Consider what to do with other states that are not within
+ // NeighborEvent#isValid() (i.e. NUD_NONE, NUD_INCOMPLETE).
+ if (event.nudState == StructNdMsg.NUD_FAILED) {
+ mLog.w("ALERT neighbor went from: " + prev + " to: " + event);
+ handleNeighborLost(event);
+ }
+ });
+ mIpNeighborMonitor.start();
}
public void stop() {
- mRunning = false;
+ mIpNeighborMonitor.stop();
clearLinkProperties();
- mNetlinkSocketObserver.clearNetlinkSocket();
}
- // TODO: add a public dump() method that can be called during a bug report.
+ public void dump(PrintWriter pw) {
+ DumpUtils.dumpAsync(
+ mIpNeighborMonitor.getHandler(),
+ new Dump() {
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(describeWatchList("\n"));
+ }
+ },
+ pw, "", 1000);
+ }
- private String describeWatchList() {
- final String delimiter = ", ";
- StringBuilder sb = new StringBuilder();
- synchronized (mLock) {
- sb.append("iface{" + mInterfaceName + "/" + mInterfaceIndex + "}, ");
- sb.append("v{" + mIpWatchListVersion + "}, ");
- sb.append("ntable=[");
- boolean firstTime = true;
- for (Map.Entry<InetAddress, Short> entry : mIpWatchList.entrySet()) {
- if (firstTime) {
- firstTime = false;
- } else {
- sb.append(delimiter);
- }
- sb.append(entry.getKey().getHostAddress() + "/" +
- StructNdMsg.stringForNudState(entry.getValue()));
- }
- sb.append("]");
+ private String describeWatchList() { return describeWatchList(" "); }
+
+ private String describeWatchList(String sep) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("iface{" + mInterfaceName + "/" + mInterfaceIndex + "}," + sep);
+ sb.append("ntable=[" + sep);
+ String delimiter = "";
+ for (Map.Entry<InetAddress, NeighborEvent> entry : mNeighborWatchList.entrySet()) {
+ sb.append(delimiter).append(entry.getKey().getHostAddress() + "/" + entry.getValue());
+ delimiter = "," + sep;
}
+ sb.append("]");
return sb.toString();
}
- private boolean isWatching(InetAddress ip) {
- synchronized (mLock) {
- return mRunning && mIpWatchList.containsKey(ip);
- }
- }
-
private static boolean isOnLink(List<RouteInfo> routes, InetAddress ip) {
for (RouteInfo route : routes) {
if (!route.hasGateway() && route.matches(ip)) {
@@ -284,13 +261,6 @@
return false;
}
- private short getNeighborStateLocked(InetAddress ip) {
- if (mIpWatchList.containsKey(ip)) {
- return mIpWatchList.get(ip);
- }
- return StructNdMsg.NUD_NONE;
- }
-
public void updateLinkProperties(LinkProperties lp) {
if (!mInterfaceName.equals(lp.getInterfaceName())) {
// TODO: figure out whether / how to cope with interface changes.
@@ -299,70 +269,63 @@
return;
}
- synchronized (mLock) {
- mLinkProperties = new LinkProperties(lp);
- Map<InetAddress, Short> newIpWatchList = new HashMap<>();
+ mLinkProperties = new LinkProperties(lp);
+ Map<InetAddress, NeighborEvent> newNeighborWatchList = new HashMap<>();
- final List<RouteInfo> routes = mLinkProperties.getRoutes();
- for (RouteInfo route : routes) {
- if (route.hasGateway()) {
- InetAddress gw = route.getGateway();
- if (isOnLink(routes, gw)) {
- newIpWatchList.put(gw, getNeighborStateLocked(gw));
- }
+ final List<RouteInfo> routes = mLinkProperties.getRoutes();
+ for (RouteInfo route : routes) {
+ if (route.hasGateway()) {
+ InetAddress gw = route.getGateway();
+ if (isOnLink(routes, gw)) {
+ newNeighborWatchList.put(gw, mNeighborWatchList.getOrDefault(gw, null));
}
}
-
- for (InetAddress nameserver : lp.getDnsServers()) {
- if (isOnLink(routes, nameserver)) {
- newIpWatchList.put(nameserver, getNeighborStateLocked(nameserver));
- }
- }
-
- mIpWatchList = newIpWatchList;
- mIpWatchListVersion++;
}
+
+ for (InetAddress dns : lp.getDnsServers()) {
+ if (isOnLink(routes, dns)) {
+ newNeighborWatchList.put(dns, mNeighborWatchList.getOrDefault(dns, null));
+ }
+ }
+
+ mNeighborWatchList = newNeighborWatchList;
if (DBG) { Log.d(TAG, "watch: " + describeWatchList()); }
}
public void clearLinkProperties() {
- synchronized (mLock) {
- mLinkProperties.clear();
- mIpWatchList.clear();
- mIpWatchListVersion++;
- }
+ mLinkProperties.clear();
+ mNeighborWatchList.clear();
if (DBG) { Log.d(TAG, "clear: " + describeWatchList()); }
}
- private void handleNeighborLost(String msg) {
+ private void handleNeighborLost(NeighborEvent event) {
+ final LinkProperties whatIfLp = new LinkProperties(mLinkProperties);
+
InetAddress ip = null;
- final ProvisioningChange delta;
- synchronized (mLock) {
- LinkProperties whatIfLp = new LinkProperties(mLinkProperties);
+ for (Map.Entry<InetAddress, NeighborEvent> entry : mNeighborWatchList.entrySet()) {
+ // TODO: Consider using NeighborEvent#isValid() here; it's more
+ // strict but may interact badly if other entries are somehow in
+ // NUD_INCOMPLETE (say, during network attach).
+ if (entry.getValue().nudState != StructNdMsg.NUD_FAILED) continue;
- for (Map.Entry<InetAddress, Short> entry : mIpWatchList.entrySet()) {
- if (entry.getValue() != StructNdMsg.NUD_FAILED) {
- continue;
- }
-
- ip = entry.getKey();
- for (RouteInfo route : mLinkProperties.getRoutes()) {
- if (ip.equals(route.getGateway())) {
- whatIfLp.removeRoute(route);
- }
- }
-
- if (avoidingBadLinks() || !(ip instanceof Inet6Address)) {
- // We should do this unconditionally, but alas we cannot: b/31827713.
- whatIfLp.removeDnsServer(ip);
+ ip = entry.getKey();
+ for (RouteInfo route : mLinkProperties.getRoutes()) {
+ if (ip.equals(route.getGateway())) {
+ whatIfLp.removeRoute(route);
}
}
- delta = LinkProperties.compareProvisioning(mLinkProperties, whatIfLp);
+ if (avoidingBadLinks() || !(ip instanceof Inet6Address)) {
+ // We should do this unconditionally, but alas we cannot: b/31827713.
+ whatIfLp.removeDnsServer(ip);
+ }
}
+ final ProvisioningChange delta = LinkProperties.compareProvisioning(
+ mLinkProperties, whatIfLp);
+
if (delta == ProvisioningChange.LOST_PROVISIONING) {
- final String logMsg = "FAILURE: LOST_PROVISIONING, " + msg;
+ final String logMsg = "FAILURE: LOST_PROVISIONING, " + event;
Log.w(TAG, logMsg);
if (mCallback != null) {
// TODO: remove |ip| when the callback signature no longer has
@@ -378,12 +341,9 @@
}
public void probeAll() {
- final List<InetAddress> ipProbeList;
- synchronized (mLock) {
- ipProbeList = new ArrayList<>(mIpWatchList.keySet());
- }
+ final List<InetAddress> ipProbeList = new ArrayList<>(mNeighborWatchList.keySet());
- if (!ipProbeList.isEmpty() && mRunning) {
+ if (!ipProbeList.isEmpty()) {
// Keep the CPU awake long enough to allow all ARP/ND
// probes a reasonable chance at success. See b/23197666.
//
@@ -394,13 +354,10 @@
}
for (InetAddress target : ipProbeList) {
- if (!mRunning) {
- break;
- }
- final int returnValue = probeNeighbor(mInterfaceIndex, target);
+ final int rval = IpNeighborMonitor.startKernelNeighborProbe(mInterfaceIndex, target);
mLog.log(String.format("put neighbor %s into NUD_PROBE state (rval=%d)",
- target.getHostAddress(), returnValue));
- logEvent(IpReachabilityEvent.PROBE, returnValue);
+ target.getHostAddress(), rval));
+ logEvent(IpReachabilityEvent.PROBE, rval);
}
mLastProbeTimeMs = SystemClock.elapsedRealtime();
}
@@ -446,153 +403,4 @@
int eventType = IpReachabilityEvent.nudFailureEventType(isFromProbe, isProvisioningLost);
mMetricsLog.log(mInterfaceName, new IpReachabilityEvent(eventType));
}
-
- // TODO: simplify the number of objects by making this extend Thread.
- private final class NetlinkSocketObserver implements Runnable {
- private NetlinkSocket mSocket;
-
- @Override
- public void run() {
- if (VDBG) { Log.d(TAG, "Starting observing thread."); }
- mRunning = true;
-
- try {
- setupNetlinkSocket();
- } catch (ErrnoException | SocketException e) {
- Log.e(TAG, "Failed to suitably initialize a netlink socket", e);
- mRunning = false;
- }
-
- while (mRunning) {
- final ByteBuffer byteBuffer;
- try {
- byteBuffer = recvKernelReply();
- } catch (ErrnoException e) {
- if (mRunning) { Log.w(TAG, "ErrnoException: ", e); }
- break;
- }
- final long whenMs = SystemClock.elapsedRealtime();
- if (byteBuffer == null) {
- continue;
- }
- parseNetlinkMessageBuffer(byteBuffer, whenMs);
- }
-
- clearNetlinkSocket();
-
- mRunning = false; // Not a no-op when ErrnoException happened.
- if (VDBG) { Log.d(TAG, "Finishing observing thread."); }
- }
-
- private void clearNetlinkSocket() {
- if (mSocket != null) {
- mSocket.close();
- }
- }
-
- // TODO: Refactor the main loop to recreate the socket upon recoverable errors.
- private void setupNetlinkSocket() throws ErrnoException, SocketException {
- clearNetlinkSocket();
- mSocket = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
-
- final NetlinkSocketAddress listenAddr = new NetlinkSocketAddress(
- 0, OsConstants.RTMGRP_NEIGH);
- mSocket.bind(listenAddr);
-
- if (VDBG) {
- final NetlinkSocketAddress nlAddr = mSocket.getLocalAddress();
- Log.d(TAG, "bound to sockaddr_nl{"
- + ((long) (nlAddr.getPortId() & 0xffffffff)) + ", "
- + nlAddr.getGroupsMask()
- + "}");
- }
- }
-
- private ByteBuffer recvKernelReply() throws ErrnoException {
- try {
- return mSocket.recvMessage(0);
- } catch (InterruptedIOException e) {
- // Interruption or other error, e.g. another thread closed our file descriptor.
- } catch (ErrnoException e) {
- if (e.errno != OsConstants.EAGAIN) {
- throw e;
- }
- }
- return null;
- }
-
- private void parseNetlinkMessageBuffer(ByteBuffer byteBuffer, long whenMs) {
- while (byteBuffer.remaining() > 0) {
- final int position = byteBuffer.position();
- final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer);
- if (nlMsg == null || nlMsg.getHeader() == null) {
- byteBuffer.position(position);
- Log.e(TAG, "unparsable netlink msg: " + NetlinkConstants.hexify(byteBuffer));
- break;
- }
-
- final int srcPortId = nlMsg.getHeader().nlmsg_pid;
- if (srcPortId != 0) {
- Log.e(TAG, "non-kernel source portId: " + ((long) (srcPortId & 0xffffffff)));
- break;
- }
-
- if (nlMsg instanceof NetlinkErrorMessage) {
- Log.e(TAG, "netlink error: " + nlMsg);
- continue;
- } else if (!(nlMsg instanceof RtNetlinkNeighborMessage)) {
- if (DBG) {
- Log.d(TAG, "non-rtnetlink neighbor msg: " + nlMsg);
- }
- continue;
- }
-
- evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs);
- }
- }
-
- private void evaluateRtNetlinkNeighborMessage(
- RtNetlinkNeighborMessage neighMsg, long whenMs) {
- final StructNdMsg ndMsg = neighMsg.getNdHeader();
- if (ndMsg == null || ndMsg.ndm_ifindex != mInterfaceIndex) {
- return;
- }
-
- final InetAddress destination = neighMsg.getDestination();
- if (!isWatching(destination)) {
- return;
- }
-
- final short msgType = neighMsg.getHeader().nlmsg_type;
- final short nudState = ndMsg.ndm_state;
- final String eventMsg = "NeighborEvent{"
- + "elapsedMs=" + whenMs + ", "
- + destination.getHostAddress() + ", "
- + "[" + NetlinkConstants.hexify(neighMsg.getLinkLayerAddress()) + "], "
- + NetlinkConstants.stringForNlMsgType(msgType) + ", "
- + StructNdMsg.stringForNudState(nudState)
- + "}";
-
- if (VDBG) {
- Log.d(TAG, neighMsg.toString());
- } else if (DBG) {
- Log.d(TAG, eventMsg);
- }
-
- synchronized (mLock) {
- if (mIpWatchList.containsKey(destination)) {
- final short value =
- (msgType == NetlinkConstants.RTM_DELNEIGH)
- ? StructNdMsg.NUD_NONE
- : nudState;
- mIpWatchList.put(destination, value);
- }
- }
-
- if (nudState == StructNdMsg.NUD_FAILED) {
- Log.w(TAG, "ALERT: " + eventMsg);
- handleNeighborLost(eventMsg);
- }
- }
- }
}
diff --git a/services/net/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java
index f5f211d..5af3c29 100644
--- a/services/net/java/android/net/netlink/NetlinkSocket.java
+++ b/services/net/java/android/net/netlink/NetlinkSocket.java
@@ -16,16 +16,24 @@
package android.net.netlink;
+import static android.system.OsConstants.AF_NETLINK;
+import static android.system.OsConstants.EIO;
+import static android.system.OsConstants.EPROTO;
+import static android.system.OsConstants.ETIMEDOUT;
+import static android.system.OsConstants.SO_RCVBUF;
+import static android.system.OsConstants.SO_RCVTIMEO;
+import static android.system.OsConstants.SO_SNDTIMEO;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOL_SOCKET;
+
import android.system.ErrnoException;
import android.system.NetlinkSocketAddress;
import android.system.Os;
-import android.system.OsConstants;
import android.system.StructTimeval;
import android.util.Log;
import libcore.io.IoUtils;
import libcore.io.Libcore;
-import java.io.Closeable;
import java.io.FileDescriptor;
import java.io.InterruptedIOException;
import java.net.SocketAddress;
@@ -37,28 +45,27 @@
/**
* NetlinkSocket
*
- * A small wrapper class to assist with AF_NETLINK socket operations.
+ * A small static class to assist with AF_NETLINK socket operations.
*
* @hide
*/
-public class NetlinkSocket implements Closeable {
+public class NetlinkSocket {
private static final String TAG = "NetlinkSocket";
- private static final int SOCKET_RECV_BUFSIZE = 64 * 1024;
- private static final int DEFAULT_RECV_BUFSIZE = 8 * 1024;
- final private FileDescriptor mDescriptor;
- private NetlinkSocketAddress mAddr;
- private long mLastRecvTimeoutMs;
- private long mLastSendTimeoutMs;
+ public static final int DEFAULT_RECV_BUFSIZE = 8 * 1024;
+ public static final int SOCKET_RECV_BUFSIZE = 64 * 1024;
public static void sendOneShotKernelMessage(int nlProto, byte[] msg) throws ErrnoException {
final String errPrefix = "Error in NetlinkSocket.sendOneShotKernelMessage";
+ final long IO_TIMEOUT = 300L;
- try (NetlinkSocket nlSocket = new NetlinkSocket(nlProto)) {
- final long IO_TIMEOUT = 300L;
- nlSocket.connectToKernel();
- nlSocket.sendMessage(msg, 0, msg.length, IO_TIMEOUT);
- final ByteBuffer bytes = nlSocket.recvMessage(IO_TIMEOUT);
+ FileDescriptor fd;
+
+ try {
+ fd = forProto(nlProto);
+ connectToKernel(fd);
+ sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT);
+ final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT);
// recvMessage() guaranteed to not return null if it did not throw.
final NetlinkMessage response = NetlinkMessage.parse(bytes);
if (response != null && response instanceof NetlinkErrorMessage &&
@@ -81,61 +88,30 @@
errmsg = response.toString();
}
Log.e(TAG, errPrefix + ", errmsg=" + errmsg);
- throw new ErrnoException(errmsg, OsConstants.EPROTO);
+ throw new ErrnoException(errmsg, EPROTO);
}
} catch (InterruptedIOException e) {
Log.e(TAG, errPrefix, e);
- throw new ErrnoException(errPrefix, OsConstants.ETIMEDOUT, e);
+ throw new ErrnoException(errPrefix, ETIMEDOUT, e);
} catch (SocketException e) {
Log.e(TAG, errPrefix, e);
- throw new ErrnoException(errPrefix, OsConstants.EIO, e);
+ throw new ErrnoException(errPrefix, EIO, e);
}
+
+ IoUtils.closeQuietly(fd);
}
- public NetlinkSocket(int nlProto) throws ErrnoException {
- mDescriptor = Os.socket(
- OsConstants.AF_NETLINK, OsConstants.SOCK_DGRAM, nlProto);
-
- Os.setsockoptInt(
- mDescriptor, OsConstants.SOL_SOCKET,
- OsConstants.SO_RCVBUF, SOCKET_RECV_BUFSIZE);
+ public static FileDescriptor forProto(int nlProto) throws ErrnoException {
+ final FileDescriptor fd = Os.socket(AF_NETLINK, SOCK_DGRAM, nlProto);
+ Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, SOCKET_RECV_BUFSIZE);
+ return fd;
}
- public NetlinkSocketAddress getLocalAddress() throws ErrnoException {
- return (NetlinkSocketAddress) Os.getsockname(mDescriptor);
+ public static void connectToKernel(FileDescriptor fd) throws ErrnoException, SocketException {
+ Os.connect(fd, (SocketAddress) (new NetlinkSocketAddress(0, 0)));
}
- public void bind(NetlinkSocketAddress localAddr) throws ErrnoException, SocketException {
- Os.bind(mDescriptor, (SocketAddress)localAddr);
- }
-
- public void connectTo(NetlinkSocketAddress peerAddr)
- throws ErrnoException, SocketException {
- Os.connect(mDescriptor, (SocketAddress) peerAddr);
- }
-
- public void connectToKernel() throws ErrnoException, SocketException {
- connectTo(new NetlinkSocketAddress(0, 0));
- }
-
- /**
- * Wait indefinitely (or until underlying socket error) for a
- * netlink message of at most DEFAULT_RECV_BUFSIZE size.
- */
- public ByteBuffer recvMessage()
- throws ErrnoException, InterruptedIOException {
- return recvMessage(DEFAULT_RECV_BUFSIZE, 0);
- }
-
- /**
- * Wait up to |timeoutMs| (or until underlying socket error) for a
- * netlink message of at most DEFAULT_RECV_BUFSIZE size.
- */
- public ByteBuffer recvMessage(long timeoutMs) throws ErrnoException, InterruptedIOException {
- return recvMessage(DEFAULT_RECV_BUFSIZE, timeoutMs);
- }
-
- private void checkTimeout(long timeoutMs) {
+ private static void checkTimeout(long timeoutMs) {
if (timeoutMs < 0) {
throw new IllegalArgumentException("Negative timeouts not permitted");
}
@@ -147,21 +123,14 @@
*
* Multi-threaded calls with different timeouts will cause unexpected results.
*/
- public ByteBuffer recvMessage(int bufsize, long timeoutMs)
+ public static ByteBuffer recvMessage(FileDescriptor fd, int bufsize, long timeoutMs)
throws ErrnoException, IllegalArgumentException, InterruptedIOException {
checkTimeout(timeoutMs);
- synchronized (mDescriptor) {
- if (mLastRecvTimeoutMs != timeoutMs) {
- Os.setsockoptTimeval(mDescriptor,
- OsConstants.SOL_SOCKET, OsConstants.SO_RCVTIMEO,
- StructTimeval.fromMillis(timeoutMs));
- mLastRecvTimeoutMs = timeoutMs;
- }
- }
+ Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs));
ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize);
- int length = Os.read(mDescriptor, byteBuffer);
+ int length = Os.read(fd, byteBuffer);
if (length == bufsize) {
Log.w(TAG, "maximum read");
}
@@ -172,39 +141,16 @@
}
/**
- * Send a message to a peer to which this socket has previously connected.
- *
- * This blocks until completion or an error occurs.
- */
- public boolean sendMessage(byte[] bytes, int offset, int count)
- throws ErrnoException, InterruptedIOException {
- return sendMessage(bytes, offset, count, 0);
- }
-
- /**
* Send a message to a peer to which this socket has previously connected,
* waiting at most |timeoutMs| milliseconds for the send to complete.
*
* Multi-threaded calls with different timeouts will cause unexpected results.
*/
- public boolean sendMessage(byte[] bytes, int offset, int count, long timeoutMs)
+ public static int sendMessage(
+ FileDescriptor fd, byte[] bytes, int offset, int count, long timeoutMs)
throws ErrnoException, IllegalArgumentException, InterruptedIOException {
checkTimeout(timeoutMs);
-
- synchronized (mDescriptor) {
- if (mLastSendTimeoutMs != timeoutMs) {
- Os.setsockoptTimeval(mDescriptor,
- OsConstants.SOL_SOCKET, OsConstants.SO_SNDTIMEO,
- StructTimeval.fromMillis(timeoutMs));
- mLastSendTimeoutMs = timeoutMs;
- }
- }
-
- return (count == Os.write(mDescriptor, bytes, offset, count));
- }
-
- @Override
- public void close() {
- IoUtils.closeQuietly(mDescriptor);
+ Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs));
+ return Os.write(fd, bytes, offset, count);
}
}
diff --git a/services/net/java/android/net/netlink/StructNdMsg.java b/services/net/java/android/net/netlink/StructNdMsg.java
index b68ec0b..e34ec39 100644
--- a/services/net/java/android/net/netlink/StructNdMsg.java
+++ b/services/net/java/android/net/netlink/StructNdMsg.java
@@ -63,6 +63,11 @@
return ((nudState & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE)) != 0);
}
+ public static boolean isNudStateValid(short nudState) {
+ return (isNudStateConnected(nudState) ||
+ ((nudState & (NUD_PROBE|NUD_STALE|NUD_DELAY)) != 0));
+ }
+
// Neighbor Cache Entry Flags
public static byte NTF_USE = (byte) 0x01;
public static byte NTF_SELF = (byte) 0x02;
@@ -143,7 +148,7 @@
}
public boolean nudValid() {
- return (nudConnected() || ((ndm_state & (NUD_PROBE|NUD_STALE|NUD_DELAY)) != 0));
+ return isNudStateValid(ndm_state);
}
@Override
diff --git a/services/net/java/android/net/util/BlockingSocketReader.java b/services/net/java/android/net/util/PacketReader.java
similarity index 97%
rename from services/net/java/android/net/util/BlockingSocketReader.java
rename to services/net/java/android/net/util/PacketReader.java
index 99bf469..10da2a5 100644
--- a/services/net/java/android/net/util/BlockingSocketReader.java
+++ b/services/net/java/android/net/util/PacketReader.java
@@ -67,7 +67,7 @@
*
* @hide
*/
-public abstract class BlockingSocketReader {
+public abstract class PacketReader {
private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR;
private static final int UNREGISTER_THIS_FD = 0;
@@ -83,11 +83,11 @@
IoUtils.closeQuietly(fd);
}
- protected BlockingSocketReader(Handler h) {
+ protected PacketReader(Handler h) {
this(h, DEFAULT_RECV_BUF_SIZE);
}
- protected BlockingSocketReader(Handler h, int recvbufsize) {
+ protected PacketReader(Handler h, int recvbufsize) {
mHandler = h;
mQueue = mHandler.getLooper().getQueue();
mPacket = new byte[Math.max(recvbufsize, DEFAULT_RECV_BUF_SIZE)];
@@ -115,6 +115,8 @@
}
}
+ public Handler getHandler() { return mHandler; }
+
public final int recvBufSize() { return mPacket.length; }
public final long numPacketsReceived() { return mPacketsReceived; }
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index e8ae020..364bbc0 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -25,6 +25,7 @@
import static com.android.internal.print.DumpUtils.writePrinterId;
import static com.android.internal.print.DumpUtils.writePrinterInfo;
import static com.android.internal.print.DumpUtils.writeStringIfNotNull;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -81,7 +82,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.BackgroundThread;
-import com.android.internal.os.SomeArgs;
import com.android.server.print.RemotePrintService.PrintServiceCallbacks;
import com.android.server.print.RemotePrintServiceRecommendationService
.RemotePrintServiceRecommendationServiceCallbacks;
@@ -462,7 +462,7 @@
if (mPrinterDiscoverySession == null) {
// If we do not have a session, tell all service to create one.
- mPrinterDiscoverySession = new PrinterDiscoverySessionMediator(mContext) {
+ mPrinterDiscoverySession = new PrinterDiscoverySessionMediator() {
@Override
public void onDestroyed() {
mPrinterDiscoverySession = null;
@@ -1141,12 +1141,8 @@
// just died. Do this off the main thread since we do to allow
// calls into the spooler on the main thread.
if (Looper.getMainLooper().isCurrentThread()) {
- BackgroundThread.getHandler().post(new Runnable() {
- @Override
- public void run() {
- failScheduledPrintJobsForServiceInternal(serviceName);
- }
- });
+ BackgroundThread.getHandler().sendMessage(obtainMessage(
+ UserState::failScheduledPrintJobsForServiceInternal, this, serviceName));
} else {
failScheduledPrintJobsForServiceInternal(serviceName);
}
@@ -1341,18 +1337,13 @@
private final List<PrinterId> mStateTrackedPrinters = new ArrayList<PrinterId>();
- private final Handler mSessionHandler;
-
private boolean mIsDestroyed;
- public PrinterDiscoverySessionMediator(Context context) {
- mSessionHandler = new SessionHandler(context.getMainLooper());
+ PrinterDiscoverySessionMediator() {
// Kick off the session creation.
- List<RemotePrintService> services = new ArrayList<RemotePrintService>(
- mActiveServices.values());
- mSessionHandler.obtainMessage(SessionHandler
- .MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION, services)
- .sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(UserState.PrinterDiscoverySessionMediator::
+ handleDispatchCreatePrinterDiscoverySession,
+ this, new ArrayList<>(mActiveServices.values())));
}
public void addObserverLocked(@NonNull IPrinterDiscoveryObserver observer) {
@@ -1361,12 +1352,9 @@
// Bring the added observer up to speed with the printers.
if (!mPrinters.isEmpty()) {
- List<PrinterInfo> printers = new ArrayList<PrinterInfo>(mPrinters.values());
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = observer;
- args.arg2 = printers;
- mSessionHandler.obtainMessage(SessionHandler.MSG_PRINTERS_ADDED,
- args).sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(
+ UserState.PrinterDiscoverySessionMediator::handlePrintersAdded,
+ this, observer, new ArrayList<>(mPrinters.values())));
}
}
@@ -1403,14 +1391,9 @@
return;
}
- List<RemotePrintService> services = new ArrayList<RemotePrintService>(
- mActiveServices.values());
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = services;
- args.arg2 = priorityList;
- mSessionHandler.obtainMessage(SessionHandler
- .MSG_DISPATCH_START_PRINTER_DISCOVERY, args)
- .sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(UserState.PrinterDiscoverySessionMediator::
+ handleDispatchStartPrinterDiscovery, this,
+ new ArrayList<>(mActiveServices.values()), priorityList));
}
public final void stopPrinterDiscoveryLocked(@NonNull IPrinterDiscoveryObserver observer) {
@@ -1426,11 +1409,9 @@
if (!mStartedPrinterDiscoveryTokens.isEmpty()) {
return;
}
- List<RemotePrintService> services = new ArrayList<RemotePrintService>(
- mActiveServices.values());
- mSessionHandler.obtainMessage(SessionHandler
- .MSG_DISPATCH_STOP_PRINTER_DISCOVERY, services)
- .sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(UserState.PrinterDiscoverySessionMediator::
+ handleDispatchStopPrinterDiscovery,
+ this, new ArrayList<>(mActiveServices.values())));
}
public void validatePrintersLocked(@NonNull List<PrinterId> printerIds) {
@@ -1461,12 +1442,9 @@
// Schedule a notification of the service.
RemotePrintService service = mActiveServices.get(serviceName);
if (service != null) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = service;
- args.arg2 = updateList;
- mSessionHandler.obtainMessage(SessionHandler
- .MSG_VALIDATE_PRINTERS, args)
- .sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(
+ UserState.PrinterDiscoverySessionMediator::handleValidatePrinters,
+ this, service, updateList));
}
}
}
@@ -1493,12 +1471,8 @@
return;
}
// Ask the service to start tracking.
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = service;
- args.arg2 = printerId;
- mSessionHandler.obtainMessage(SessionHandler
- .MSG_START_PRINTER_STATE_TRACKING, args)
- .sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(UserState.PrinterDiscoverySessionMediator::
+ handleStartPrinterStateTracking, this, service, printerId));
}
public final void stopPrinterStateTrackingLocked(PrinterId printerId) {
@@ -1520,12 +1494,8 @@
return;
}
// Ask the service to start tracking.
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = service;
- args.arg2 = printerId;
- mSessionHandler.obtainMessage(SessionHandler
- .MSG_STOP_PRINTER_STATE_TRACKING, args)
- .sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(UserState.PrinterDiscoverySessionMediator::
+ handleStopPrinterStateTracking, this, service, printerId));
}
public void onDestroyed() {
@@ -1551,11 +1521,9 @@
stopPrinterDiscoveryLocked(IPrinterDiscoveryObserver.Stub.asInterface(token));
}
// Tell the services we are done.
- List<RemotePrintService> services = new ArrayList<RemotePrintService>(
- mActiveServices.values());
- mSessionHandler.obtainMessage(SessionHandler
- .MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION, services)
- .sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(UserState.PrinterDiscoverySessionMediator::
+ handleDispatchDestroyPrinterDiscoverySession,
+ this, new ArrayList<>(mActiveServices.values())));
}
public void onPrintersAddedLocked(List<PrinterInfo> printers) {
@@ -1579,8 +1547,9 @@
}
}
if (addedPrinters != null) {
- mSessionHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED,
- addedPrinters).sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(
+ UserState.PrinterDiscoverySessionMediator::handleDispatchPrintersAdded,
+ this, addedPrinters));
}
}
@@ -1604,8 +1573,9 @@
}
}
if (removedPrinterIds != null) {
- mSessionHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
- removedPrinterIds).sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(
+ UserState.PrinterDiscoverySessionMediator::handleDispatchPrintersRemoved,
+ this, removedPrinterIds));
}
}
@@ -1646,8 +1616,9 @@
ArrayList<PrinterInfo> addedPrinters = new ArrayList<>(1);
addedPrinters.add(newPrinter);
- mSessionHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED,
- addedPrinters).sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(
+ UserState.PrinterDiscoverySessionMediator::handleDispatchPrintersAdded,
+ this, addedPrinters));
}
}
@@ -1661,26 +1632,20 @@
return;
}
// Tell the service to create a session.
- mSessionHandler.obtainMessage(
- SessionHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION,
- service).sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(
+ RemotePrintService::createPrinterDiscoverySession, service));
// Start printer discovery if necessary.
if (!mStartedPrinterDiscoveryTokens.isEmpty()) {
- mSessionHandler.obtainMessage(
- SessionHandler.MSG_START_PRINTER_DISCOVERY,
- service).sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(
+ RemotePrintService::startPrinterDiscovery, service, null));
}
// Start tracking printers if necessary
final int trackedPrinterCount = mStateTrackedPrinters.size();
for (int i = 0; i < trackedPrinterCount; i++) {
PrinterId printerId = mStateTrackedPrinters.get(i);
if (printerId.getServiceName().equals(service.getComponentName())) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = service;
- args.arg2 = printerId;
- mSessionHandler.obtainMessage(SessionHandler
- .MSG_START_PRINTER_STATE_TRACKING, args)
- .sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(
+ RemotePrintService::startPrinterStateTracking, service, printerId));
}
}
}
@@ -1781,9 +1746,9 @@
for (int i = 0; i < removedPrinterCount; i++) {
mPrinters.remove(removedPrinterIds.get(i));
}
- mSessionHandler.obtainMessage(
- SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
- removedPrinterIds).sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(
+ UserState.PrinterDiscoverySessionMediator::handleDispatchPrintersRemoved,
+ this, removedPrinterIds));
}
}
@@ -1873,134 +1838,6 @@
Log.e(LOG_TAG, "Error sending removed printers", re);
}
}
-
- private final class SessionHandler extends Handler {
- public static final int MSG_PRINTERS_ADDED = 1;
- public static final int MSG_PRINTERS_REMOVED = 2;
- public static final int MSG_DISPATCH_PRINTERS_ADDED = 3;
- public static final int MSG_DISPATCH_PRINTERS_REMOVED = 4;
-
- public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 5;
- public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 6;
- public static final int MSG_START_PRINTER_DISCOVERY = 7;
- public static final int MSG_STOP_PRINTER_DISCOVERY = 8;
- public static final int MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION = 9;
- public static final int MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION = 10;
- public static final int MSG_DISPATCH_START_PRINTER_DISCOVERY = 11;
- public static final int MSG_DISPATCH_STOP_PRINTER_DISCOVERY = 12;
- public static final int MSG_VALIDATE_PRINTERS = 13;
- public static final int MSG_START_PRINTER_STATE_TRACKING = 14;
- public static final int MSG_STOP_PRINTER_STATE_TRACKING = 15;
- public static final int MSG_DESTROY_SERVICE = 16;
-
- SessionHandler(Looper looper) {
- super(looper, null, false);
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public void handleMessage(Message message) {
- switch (message.what) {
- case MSG_PRINTERS_ADDED: {
- SomeArgs args = (SomeArgs) message.obj;
- IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) args.arg1;
- List<PrinterInfo> addedPrinters = (List<PrinterInfo>) args.arg2;
- args.recycle();
- handlePrintersAdded(observer, addedPrinters);
- } break;
-
- case MSG_PRINTERS_REMOVED: {
- SomeArgs args = (SomeArgs) message.obj;
- IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) args.arg1;
- List<PrinterId> removedPrinterIds = (List<PrinterId>) args.arg2;
- args.recycle();
- handlePrintersRemoved(observer, removedPrinterIds);
- }
-
- case MSG_DISPATCH_PRINTERS_ADDED: {
- List<PrinterInfo> addedPrinters = (List<PrinterInfo>) message.obj;
- handleDispatchPrintersAdded(addedPrinters);
- } break;
-
- case MSG_DISPATCH_PRINTERS_REMOVED: {
- List<PrinterId> removedPrinterIds = (List<PrinterId>) message.obj;
- handleDispatchPrintersRemoved(removedPrinterIds);
- } break;
-
- case MSG_CREATE_PRINTER_DISCOVERY_SESSION: {
- RemotePrintService service = (RemotePrintService) message.obj;
- service.createPrinterDiscoverySession();
- } break;
-
- case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: {
- RemotePrintService service = (RemotePrintService) message.obj;
- service.destroyPrinterDiscoverySession();
- } break;
-
- case MSG_START_PRINTER_DISCOVERY: {
- RemotePrintService service = (RemotePrintService) message.obj;
- service.startPrinterDiscovery(null);
- } break;
-
- case MSG_STOP_PRINTER_DISCOVERY: {
- RemotePrintService service = (RemotePrintService) message.obj;
- service.stopPrinterDiscovery();
- } break;
-
- case MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION: {
- List<RemotePrintService> services = (List<RemotePrintService>) message.obj;
- handleDispatchCreatePrinterDiscoverySession(services);
- } break;
-
- case MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION: {
- List<RemotePrintService> services = (List<RemotePrintService>) message.obj;
- handleDispatchDestroyPrinterDiscoverySession(services);
- } break;
-
- case MSG_DISPATCH_START_PRINTER_DISCOVERY: {
- SomeArgs args = (SomeArgs) message.obj;
- List<RemotePrintService> services = (List<RemotePrintService>) args.arg1;
- List<PrinterId> printerIds = (List<PrinterId>) args.arg2;
- args.recycle();
- handleDispatchStartPrinterDiscovery(services, printerIds);
- } break;
-
- case MSG_DISPATCH_STOP_PRINTER_DISCOVERY: {
- List<RemotePrintService> services = (List<RemotePrintService>) message.obj;
- handleDispatchStopPrinterDiscovery(services);
- } break;
-
- case MSG_VALIDATE_PRINTERS: {
- SomeArgs args = (SomeArgs) message.obj;
- RemotePrintService service = (RemotePrintService) args.arg1;
- List<PrinterId> printerIds = (List<PrinterId>) args.arg2;
- args.recycle();
- handleValidatePrinters(service, printerIds);
- } break;
-
- case MSG_START_PRINTER_STATE_TRACKING: {
- SomeArgs args = (SomeArgs) message.obj;
- RemotePrintService service = (RemotePrintService) args.arg1;
- PrinterId printerId = (PrinterId) args.arg2;
- args.recycle();
- handleStartPrinterStateTracking(service, printerId);
- } break;
-
- case MSG_STOP_PRINTER_STATE_TRACKING: {
- SomeArgs args = (SomeArgs) message.obj;
- RemotePrintService service = (RemotePrintService) args.arg1;
- PrinterId printerId = (PrinterId) args.arg2;
- args.recycle();
- handleStopPrinterStateTracking(service, printerId);
- } break;
-
- case MSG_DESTROY_SERVICE: {
- RemotePrintService service = (RemotePrintService) message.obj;
- service.destroy();
- } break;
- }
- }
- }
}
private final class PrintJobForAppCache {
diff --git a/services/robotests/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
index 2824b35..3d5851f 100644
--- a/services/robotests/src/com/android/server/backup/TransportManagerTest.java
+++ b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
@@ -36,6 +36,7 @@
import com.android.server.backup.testing.ShadowContextImplForBackup;
import com.android.server.backup.testing.TransportBoundListenerStub;
import com.android.server.backup.testing.TransportReadyCallbackStub;
+import com.android.server.backup.transport.TransportClient;
import org.junit.After;
import org.junit.Before;
@@ -475,6 +476,62 @@
assertThat(mTransportReadyCallbackStub.getFailureCalls()).isEmpty();
}
+ @Test
+ public void getTransportClient_forRegisteredTransport_returnCorrectly() throws Exception {
+ TransportManager transportManager =
+ createTransportManagerAndSetUpTransports(
+ Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+
+ TransportClient transportClient =
+ transportManager.getTransportClient(mTransport1.name, "caller");
+
+ assertThat(transportClient.getTransportComponent()).isEqualTo(mTransport1.componentName);
+ }
+
+ @Test
+ public void getTransportClient_forOldNameOfTransportThatChangedName_returnsNull()
+ throws Exception {
+ TransportManager transportManager =
+ createTransportManagerAndSetUpTransports(
+ Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+ transportManager.describeTransport(
+ mTransport1.componentName, "newName", null, "destinationString", null, null);
+
+ TransportClient transportClient =
+ transportManager.getTransportClient(mTransport1.name, "caller");
+
+ assertThat(transportClient).isNull();
+ }
+
+ @Test
+ public void getTransportClient_forNewNameOfTransportThatChangedName_returnsCorrectly()
+ throws Exception {
+ TransportManager transportManager =
+ createTransportManagerAndSetUpTransports(
+ Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+ transportManager.describeTransport(
+ mTransport1.componentName, "newName", null, "destinationString", null, null);
+
+ TransportClient transportClient =
+ transportManager.getTransportClient("newName", "caller");
+
+ assertThat(transportClient.getTransportComponent()).isEqualTo(mTransport1.componentName);
+ }
+
+ @Test
+ public void getTransportName_forTransportThatChangedName_returnsNewName()
+ throws Exception {
+ TransportManager transportManager =
+ createTransportManagerAndSetUpTransports(
+ Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+ transportManager.describeTransport(
+ mTransport1.componentName, "newName", null, "destinationString", null, null);
+
+ String transportName = transportManager.getTransportName(mTransport1.componentName);
+
+ assertThat(transportName).isEqualTo("newName");
+ }
+
private void setUpPackageWithTransports(String packageName, List<TransportInfo> transports,
int flags) throws Exception {
PackageInfo packageInfo = new PackageInfo();
diff --git a/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java b/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
index 54d233a..4a3277f 100644
--- a/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
+++ b/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
@@ -17,6 +17,7 @@
package com.android.server.backup.transport;
import static com.android.server.backup.TransportManager.SERVICE_ACTION_TRANSPORT_HOST;
+import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -54,6 +55,7 @@
private static final String PACKAGE_NAME = "some.package.name";
private static final ComponentName TRANSPORT_COMPONENT =
new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".transport.Transport");
+ private static final String TRANSPORT_DIR_NAME = TRANSPORT_COMPONENT.toString();
@Mock private Context mContext;
@Mock private TransportConnectionListener mTransportConnectionListener;
@@ -72,7 +74,12 @@
mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(TRANSPORT_COMPONENT);
mTransportClient =
new TransportClient(
- mContext, mBindIntent, TRANSPORT_COMPONENT, "1", new Handler(mainLooper));
+ mContext,
+ mBindIntent,
+ TRANSPORT_COMPONENT,
+ TRANSPORT_DIR_NAME,
+ "1",
+ new Handler(mainLooper));
when(mContext.bindServiceAsUser(
eq(mBindIntent),
@@ -82,7 +89,16 @@
.thenReturn(true);
}
- // TODO: Testing implementation? Remove?
+ @Test
+ public void testGetTransportDirName_returnsTransportDirName() {
+ assertThat(mTransportClient.getTransportDirName()).isEqualTo(TRANSPORT_DIR_NAME);
+ }
+
+ @Test
+ public void testGetTransportComponent_returnsTransportComponent() {
+ assertThat(mTransportClient.getTransportComponent()).isEqualTo(TRANSPORT_COMPONENT);
+ }
+
@Test
public void testConnectAsync_callsBindService() throws Exception {
mTransportClient.connectAsync(mTransportConnectionListener, "caller");
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index a2ec234..218a2b8 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -26,6 +26,7 @@
platform-test-annotations \
ShortcutManagerTestUtils \
truth-prebuilt \
+ testables \
testng
LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
@@ -37,7 +38,7 @@
LOCAL_JAVA_LIBRARIES := \
android.hidl.manager-V1.0-java \
android.test.mock \
- legacy-android-test \
+ android.test.base android.test.runner \
LOCAL_PACKAGE_NAME := FrameworksServicesTests
LOCAL_COMPATIBILITY_SUITE := device-tests
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 9a5ebed..0499bf0 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -58,6 +58,7 @@
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
+ <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
<!-- Uses API introduced in O (26) -->
<uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/AlarmManagerServiceTest.java
new file mode 100644
index 0000000..918807d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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;
+
+import static android.app.AlarmManager.RTC;
+import static android.app.AlarmManager.RTC_WAKEUP;
+
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.SparseArray;
+
+import com.android.internal.util.ObjectUtils;
+import com.android.server.AlarmManagerService.Alarm;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AlarmManagerServiceTest {
+ private SparseArray<ArrayList<Alarm>> addPendingAlarm(
+ SparseArray<ArrayList<Alarm>> all, int uid, String name, boolean removeIt) {
+ ArrayList<Alarm> uidAlarms = all.get(uid);
+ if (uidAlarms == null) {
+ all.put(uid, uidAlarms = new ArrayList<>());
+ }
+ // Details don't matter.
+ uidAlarms.add(new Alarm(
+ removeIt ? RTC : RTC_WAKEUP,
+ 0, 0, 0, 0, 0, null, null, null, null, 0, null, uid, name));
+ return all;
+ }
+
+ private static String toString(SparseArray<ArrayList<Alarm>> pendingAlarms) {
+ final StringBuilder sb = new StringBuilder();
+
+ String sep = "";
+ for (int i = 0; i < pendingAlarms.size(); i++) {
+ sb.append(sep);
+ sep = ", ";
+ sb.append("[");
+ sb.append(pendingAlarms.keyAt(i));
+ sb.append(": ");
+ sb.append(toString(pendingAlarms.valueAt(i)));
+ sb.append("]");
+ }
+ return sb.toString();
+ }
+
+ private static String toString(ArrayList<Alarm> alarms) {
+ final StringBuilder sb = new StringBuilder();
+
+ alarms.sort((a, b) -> ObjectUtils.compare(a.packageName, b.packageName));
+
+ String sep = "";
+ for (Alarm a : alarms) {
+ sb.append(sep);
+ sep = ", ";
+ sb.append(a.packageName);
+ }
+ return sb.toString();
+ }
+
+ private void runCheckAllPendingAlarms(
+ SparseArray<ArrayList<Alarm>> pending, ArrayList<Alarm> alarmsToDeliver) {
+ // RTC_WAKEUP alarms are restricted.
+ AlarmManagerService.findAllUnrestrictedPendingBackgroundAlarmsLockedInner(pending,
+ alarmsToDeliver, alarm -> alarm.type == RTC_WAKEUP);
+ }
+
+ @Test
+ public void findAllUnrestrictedPendingBackgroundAlarmsLockedInner_empty() {
+ SparseArray<ArrayList<Alarm>> pending = new SparseArray<>();
+
+ final ArrayList<Alarm> alarmsToDeliver = new ArrayList<>();
+
+ runCheckAllPendingAlarms(pending, alarmsToDeliver);
+
+ assertEquals("", toString(pending));
+ assertEquals("", toString(alarmsToDeliver));
+ }
+
+ @Test
+ public void findAllUnrestrictedPendingBackgroundAlarmsLockedInner_single_remove() {
+ SparseArray<ArrayList<Alarm>> pending = new SparseArray<>();
+
+ addPendingAlarm(pending, 100001, "a1", false);
+
+ final ArrayList<Alarm> alarmsToDeliver = new ArrayList<>();
+
+ runCheckAllPendingAlarms(pending, alarmsToDeliver);
+
+ assertEquals("[100001: a1]", toString(pending));
+ assertEquals("", toString(alarmsToDeliver));
+ }
+
+ @Test
+ public void findAllUnrestrictedPendingBackgroundAlarmsLockedInner_single_nonremove() {
+ SparseArray<ArrayList<Alarm>> pending = new SparseArray<>();
+
+ addPendingAlarm(pending, 100001, "a1", true);
+
+ final ArrayList<Alarm> alarmsToDeliver = new ArrayList<>();
+ runCheckAllPendingAlarms(pending, alarmsToDeliver);
+
+
+ assertEquals("", toString(pending));
+ assertEquals("a1", toString(alarmsToDeliver));
+ }
+
+ @Test
+ public void findAllUnrestrictedPendingBackgroundAlarmsLockedInner_complex() {
+ SparseArray<ArrayList<Alarm>> pending = new SparseArray<>();
+
+ addPendingAlarm(pending, 100001, "a11", false);
+ addPendingAlarm(pending, 100001, "a12", true);
+ addPendingAlarm(pending, 100001, "a13", false);
+ addPendingAlarm(pending, 100001, "a14", true);
+
+ addPendingAlarm(pending, 100002, "a21", false);
+
+ addPendingAlarm(pending, 100003, "a31", true);
+
+ addPendingAlarm(pending, 100004, "a41", false);
+ addPendingAlarm(pending, 100004, "a42", false);
+
+ addPendingAlarm(pending, 100005, "a51", true);
+ addPendingAlarm(pending, 100005, "a52", true);
+
+ addPendingAlarm(pending, 100006, "a61", true);
+ addPendingAlarm(pending, 100006, "a62", false);
+ addPendingAlarm(pending, 100006, "a63", true);
+ addPendingAlarm(pending, 100006, "a64", false);
+
+ final ArrayList<Alarm> alarmsToDeliver = new ArrayList<>();
+ runCheckAllPendingAlarms(pending, alarmsToDeliver);
+
+
+ assertEquals("[100001: a11, a13], [100002: a21], [100004: a41, a42], [100006: a62, a64]",
+ toString(pending));
+ assertEquals("a12, a14, a31, a51, a52, a61, a63", toString(alarmsToDeliver));
+ }
+
+ @Test
+ public void findAllUnrestrictedPendingBackgroundAlarmsLockedInner_complex_allRemove() {
+ SparseArray<ArrayList<Alarm>> pending = new SparseArray<>();
+
+ addPendingAlarm(pending, 100001, "a11", true);
+ addPendingAlarm(pending, 100001, "a12", true);
+ addPendingAlarm(pending, 100001, "a13", true);
+ addPendingAlarm(pending, 100001, "a14", true);
+
+ addPendingAlarm(pending, 100002, "a21", true);
+
+ addPendingAlarm(pending, 100003, "a31", true);
+
+ addPendingAlarm(pending, 100004, "a41", true);
+ addPendingAlarm(pending, 100004, "a42", true);
+
+ addPendingAlarm(pending, 100005, "a51", true);
+ addPendingAlarm(pending, 100005, "a52", true);
+
+ addPendingAlarm(pending, 100006, "a61", true);
+ addPendingAlarm(pending, 100006, "a62", true);
+ addPendingAlarm(pending, 100006, "a63", true);
+ addPendingAlarm(pending, 100006, "a64", true);
+
+ final ArrayList<Alarm> alarmsToDeliver = new ArrayList<>();
+ runCheckAllPendingAlarms(pending, alarmsToDeliver);
+
+
+ assertEquals("", toString(pending));
+ assertEquals("a11, a12, a13, a14, a21, a31, a41, a42, a51, a52, a61, a62, a63, a64",
+ toString(alarmsToDeliver));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java b/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
new file mode 100644
index 0000000..66d0da1
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
@@ -0,0 +1,900 @@
+/*
+ * 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;
+
+import static com.android.server.ForceAppStandbyTracker.TARGET_OP;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+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.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.AppOpsManager.OpEntry;
+import android.app.AppOpsManager.PackageOps;
+import android.app.IActivityManager;
+import android.app.IUidObserver;
+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.PowerManager.ServiceType;
+import android.os.PowerManagerInternal;
+import android.os.PowerSaveState;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.ArraySet;
+import android.util.Pair;
+
+import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsService;
+import com.android.server.ForceAppStandbyTracker.Listener;
+
+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.Arrays;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ForceAppStandbyTrackerTest {
+
+ private class ForceAppStandbyTrackerTestable extends ForceAppStandbyTracker {
+ ForceAppStandbyTrackerTestable() {
+ super(mMockContext, Looper.getMainLooper());
+ }
+
+ @Override
+ AppOpsManager injectAppOpsManager() {
+ return mMockAppOpsManager;
+ }
+
+ @Override
+ IAppOpsService injectIAppOpsService() {
+ return mMockIAppOpsService;
+ }
+
+ @Override
+ IActivityManager injectIActivityManager() {
+ return mMockIActivityManager;
+ }
+
+ @Override
+ PowerManagerInternal injectPowerManagerInternal() {
+ return mMockPowerManagerInternal;
+ }
+ }
+
+ private static final int UID_1 = Process.FIRST_APPLICATION_UID + 1;
+ private static final int UID_2 = Process.FIRST_APPLICATION_UID + 2;
+ private static final int UID_3 = Process.FIRST_APPLICATION_UID + 3;
+ private static final int UID_10_1 = UserHandle.getUid(10, UID_1);
+ private static final int UID_10_2 = UserHandle.getUid(10, UID_2);
+ private static final int UID_10_3 = UserHandle.getUid(10, UID_3);
+ private static final String PACKAGE_1 = "package1";
+ private static final String PACKAGE_2 = "package2";
+ private static final String PACKAGE_3 = "package3";
+ private static final String PACKAGE_SYSTEM = "android";
+
+ private Handler mMainHandler;
+
+ @Mock
+ private Context mMockContext;
+
+ @Mock
+ private IActivityManager mMockIActivityManager;
+
+ @Mock
+ private AppOpsManager mMockAppOpsManager;
+
+ @Mock
+ private IAppOpsService mMockIAppOpsService;
+
+ @Mock
+ private PowerManagerInternal mMockPowerManagerInternal;
+
+ private IUidObserver mIUidObserver;
+ private IAppOpsCallback.Stub mAppOpsCallback;
+ private Consumer<PowerSaveState> mPowerSaveObserver;
+ private BroadcastReceiver mReceiver;
+
+ private boolean mPowerSaveMode;
+
+ private final ArraySet<Pair<Integer, String>> mRestrictedPackages = new ArraySet();
+
+ @Before
+ public void setUp() {
+ mMainHandler = new Handler(Looper.getMainLooper());
+ }
+
+ private void waitUntilMainHandlerDrain() throws Exception {
+ final CountDownLatch l = new CountDownLatch(1);
+ mMainHandler.post(() -> {
+ l.countDown();
+ });
+ assertTrue(l.await(5, TimeUnit.SECONDS));
+ }
+
+ private PowerSaveState getPowerSaveState() {
+ return new PowerSaveState.Builder().setBatterySaverEnabled(mPowerSaveMode).build();
+ }
+
+ private ForceAppStandbyTrackerTestable newInstance() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ when(mMockIAppOpsService.checkOperation(eq(TARGET_OP), anyInt(), anyString()))
+ .thenAnswer(inv -> {
+ return mRestrictedPackages.indexOf(
+ Pair.create(inv.getArgument(1), inv.getArgument(2))) >= 0 ?
+ AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED;
+ });
+
+ final ForceAppStandbyTrackerTestable instance = new ForceAppStandbyTrackerTestable();
+
+ return instance;
+ }
+
+ private void callStart(ForceAppStandbyTrackerTestable instance) throws RemoteException {
+
+ // Set up functions that start() calls.
+ when(mMockPowerManagerInternal.getLowPowerState(eq(ServiceType.FORCE_ALL_APPS_STANDBY)))
+ .thenAnswer(inv -> getPowerSaveState());
+ when(mMockAppOpsManager.getPackagesForOps(
+ any(int[].class)
+ )).thenAnswer(inv -> new ArrayList<AppOpsManager.PackageOps>());
+
+ // Call start.
+ instance.start();
+
+ // Capture the listeners.
+ ArgumentCaptor<IUidObserver> uidObserverArgumentCaptor =
+ ArgumentCaptor.forClass(IUidObserver.class);
+ ArgumentCaptor<IAppOpsCallback.Stub> appOpsCallbackCaptor =
+ ArgumentCaptor.forClass(IAppOpsCallback.Stub.class);
+ ArgumentCaptor<Consumer<PowerSaveState>> powerSaveObserverCaptor =
+ ArgumentCaptor.forClass(Consumer.class);
+ ArgumentCaptor<BroadcastReceiver> receiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+
+ verify(mMockIActivityManager).registerUidObserver(
+ uidObserverArgumentCaptor.capture(),
+ eq(ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_IDLE
+ | ActivityManager.UID_OBSERVER_ACTIVE),
+ eq(ActivityManager.PROCESS_STATE_UNKNOWN),
+ isNull());
+ verify(mMockIAppOpsService).startWatchingMode(
+ eq(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND),
+ isNull(),
+ appOpsCallbackCaptor.capture());
+ verify(mMockPowerManagerInternal).registerLowPowerModeObserver(
+ eq(ServiceType.FORCE_ALL_APPS_STANDBY),
+ powerSaveObserverCaptor.capture());
+
+ verify(mMockContext).registerReceiver(
+ receiverCaptor.capture(), any(IntentFilter.class));
+
+ mIUidObserver = uidObserverArgumentCaptor.getValue();
+ mAppOpsCallback = appOpsCallbackCaptor.getValue();
+ mPowerSaveObserver = powerSaveObserverCaptor.getValue();
+ mReceiver = receiverCaptor.getValue();
+
+ assertNotNull(mIUidObserver);
+ assertNotNull(mAppOpsCallback);
+ assertNotNull(mPowerSaveObserver);
+ assertNotNull(mReceiver);
+ }
+
+ private void setAppOps(int uid, String packageName, boolean restrict) throws RemoteException {
+ final Pair p = Pair.create(uid, packageName);
+ if (restrict) {
+ mRestrictedPackages.add(p);
+ } else {
+ mRestrictedPackages.remove(p);
+ }
+ if (mAppOpsCallback != null) {
+ mAppOpsCallback.opChanged(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName);
+ }
+ }
+
+ private static final int NONE = 0;
+ private static final int ALARMS_ONLY = 1 << 0;
+ private static final int JOBS_ONLY = 1 << 1;
+ private static final int JOBS_AND_ALARMS = ALARMS_ONLY | JOBS_ONLY;
+
+ private void areRestricted(ForceAppStandbyTrackerTestable instance, int uid, String packageName,
+ int restrictionTypes) {
+ assertEquals(((restrictionTypes & JOBS_ONLY) != 0),
+ instance.areJobsRestricted(uid, packageName));
+ assertEquals(((restrictionTypes & ALARMS_ONLY) != 0),
+ instance.areAlarmsRestricted(uid, packageName));
+ }
+
+ @Test
+ public void testAll() throws Exception {
+ final ForceAppStandbyTrackerTestable instance = newInstance();
+ callStart(instance);
+
+ assertFalse(instance.isForceAllAppsStandbyEnabled());
+ areRestricted(instance, UID_1, PACKAGE_1, NONE);
+ areRestricted(instance, UID_2, PACKAGE_2, NONE);
+ areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
+
+ mPowerSaveMode = true;
+ mPowerSaveObserver.accept(getPowerSaveState());
+
+ assertTrue(instance.isForceAllAppsStandbyEnabled());
+
+ areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS);
+ areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
+ areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
+
+ // Toggle the foreground state.
+ mPowerSaveMode = true;
+ mPowerSaveObserver.accept(getPowerSaveState());
+
+ assertFalse(instance.isInForeground(UID_1));
+ assertFalse(instance.isInForeground(UID_2));
+ assertTrue(instance.isInForeground(Process.SYSTEM_UID));
+
+ mIUidObserver.onUidActive(UID_1);
+ areRestricted(instance, UID_1, PACKAGE_1, NONE);
+ areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
+ areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
+ assertTrue(instance.isInForeground(UID_1));
+ assertFalse(instance.isInForeground(UID_2));
+
+ mIUidObserver.onUidGone(UID_1, /*disable=*/ false);
+ areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS);
+ areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
+ areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
+ assertFalse(instance.isInForeground(UID_1));
+ assertFalse(instance.isInForeground(UID_2));
+
+ mIUidObserver.onUidActive(UID_1);
+ areRestricted(instance, UID_1, PACKAGE_1, NONE);
+ areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
+ areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
+
+ mIUidObserver.onUidIdle(UID_1, /*disable=*/ false);
+ areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS);
+ areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
+ areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
+ assertFalse(instance.isInForeground(UID_1));
+ assertFalse(instance.isInForeground(UID_2));
+
+ // Toggle the app ops.
+ mPowerSaveMode = false;
+ mPowerSaveObserver.accept(getPowerSaveState());
+
+ assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_1, PACKAGE_1));
+ assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_1, PACKAGE_1));
+ assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_2, PACKAGE_2));
+ assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2));
+
+ areRestricted(instance, UID_1, PACKAGE_1, NONE);
+ areRestricted(instance, UID_10_1, PACKAGE_1, NONE);
+ areRestricted(instance, UID_2, PACKAGE_2, NONE);
+ areRestricted(instance, UID_10_2, PACKAGE_2, NONE);
+ areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
+
+ setAppOps(UID_1, PACKAGE_1, true);
+ setAppOps(UID_10_2, PACKAGE_2, true);
+ assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_1, PACKAGE_1));
+ assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_1, PACKAGE_1));
+ assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_2, PACKAGE_2));
+ assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2));
+
+ areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS);
+ areRestricted(instance, UID_10_1, PACKAGE_1, NONE);
+ areRestricted(instance, UID_2, PACKAGE_2, NONE);
+ areRestricted(instance, UID_10_2, PACKAGE_2, JOBS_AND_ALARMS);
+ areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
+
+ // Toggle power saver, should still be the same.
+ mPowerSaveMode = true;
+ mPowerSaveObserver.accept(getPowerSaveState());
+
+ mPowerSaveMode = false;
+ mPowerSaveObserver.accept(getPowerSaveState());
+
+ areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS);
+ areRestricted(instance, UID_10_1, PACKAGE_1, NONE);
+ areRestricted(instance, UID_2, PACKAGE_2, NONE);
+ areRestricted(instance, UID_10_2, PACKAGE_2, JOBS_AND_ALARMS);
+ areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
+
+ // Clear the app ops and update the whitelist.
+ setAppOps(UID_1, PACKAGE_1, false);
+ setAppOps(UID_10_2, PACKAGE_2, false);
+
+ mPowerSaveMode = true;
+ mPowerSaveObserver.accept(getPowerSaveState());
+
+ areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS);
+ areRestricted(instance, UID_10_1, PACKAGE_1, JOBS_AND_ALARMS);
+ areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
+ areRestricted(instance, UID_10_2, PACKAGE_2, JOBS_AND_ALARMS);
+ areRestricted(instance, UID_3, PACKAGE_3, JOBS_AND_ALARMS);
+ areRestricted(instance, UID_10_3, PACKAGE_3, JOBS_AND_ALARMS);
+ areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
+
+ instance.setPowerSaveWhitelistAppIds(new int[] {UID_1}, new int[] {UID_2});
+
+ areRestricted(instance, UID_1, PACKAGE_1, NONE);
+ areRestricted(instance, UID_10_1, PACKAGE_1, NONE);
+ areRestricted(instance, UID_2, PACKAGE_2, ALARMS_ONLY);
+ areRestricted(instance, UID_10_2, PACKAGE_2, ALARMS_ONLY);
+ areRestricted(instance, UID_3, PACKAGE_3, JOBS_AND_ALARMS);
+ areRestricted(instance, UID_10_3, PACKAGE_3, JOBS_AND_ALARMS);
+ areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
+
+ // Again, make sure toggling the global state doesn't change it.
+ mPowerSaveMode = false;
+ mPowerSaveObserver.accept(getPowerSaveState());
+
+ mPowerSaveMode = true;
+ mPowerSaveObserver.accept(getPowerSaveState());
+
+ areRestricted(instance, UID_1, PACKAGE_1, NONE);
+ areRestricted(instance, UID_10_1, PACKAGE_1, NONE);
+ areRestricted(instance, UID_2, PACKAGE_2, ALARMS_ONLY);
+ areRestricted(instance, UID_10_2, PACKAGE_2, ALARMS_ONLY);
+ areRestricted(instance, UID_3, PACKAGE_3, JOBS_AND_ALARMS);
+ areRestricted(instance, UID_10_3, PACKAGE_3, JOBS_AND_ALARMS);
+ areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
+
+ assertTrue(instance.isUidPowerSaveWhitelisted(UID_1));
+ assertTrue(instance.isUidPowerSaveWhitelisted(UID_10_1));
+ assertFalse(instance.isUidPowerSaveWhitelisted(UID_2));
+ assertFalse(instance.isUidPowerSaveWhitelisted(UID_10_2));
+
+ assertFalse(instance.isUidTempPowerSaveWhitelisted(UID_1));
+ assertFalse(instance.isUidTempPowerSaveWhitelisted(UID_10_1));
+ assertTrue(instance.isUidTempPowerSaveWhitelisted(UID_2));
+ assertTrue(instance.isUidTempPowerSaveWhitelisted(UID_10_2));
+ }
+
+ public void loadPersistedAppOps() throws Exception {
+ final ForceAppStandbyTrackerTestable instance = newInstance();
+
+ final List<PackageOps> ops = new ArrayList<>();
+
+ //--------------------------------------------------
+ List<OpEntry> entries = new ArrayList<>();
+ entries.add(new AppOpsManager.OpEntry(
+ AppOpsManager.OP_ACCESS_NOTIFICATIONS,
+ AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
+ entries.add(new AppOpsManager.OpEntry(
+ ForceAppStandbyTracker.TARGET_OP,
+ AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
+
+ ops.add(new PackageOps(PACKAGE_1, UID_1, entries));
+
+ //--------------------------------------------------
+ entries = new ArrayList<>();
+ entries.add(new AppOpsManager.OpEntry(
+ ForceAppStandbyTracker.TARGET_OP,
+ AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
+
+ ops.add(new PackageOps(PACKAGE_2, UID_2, entries));
+
+ //--------------------------------------------------
+ entries = new ArrayList<>();
+ entries.add(new AppOpsManager.OpEntry(
+ ForceAppStandbyTracker.TARGET_OP,
+ AppOpsManager.MODE_ALLOWED, 0, 0, 0, 0, null));
+
+ ops.add(new PackageOps(PACKAGE_1, UID_10_1, entries));
+
+ //--------------------------------------------------
+ entries = new ArrayList<>();
+ entries.add(new AppOpsManager.OpEntry(
+ ForceAppStandbyTracker.TARGET_OP,
+ AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
+ entries.add(new AppOpsManager.OpEntry(
+ AppOpsManager.OP_ACCESS_NOTIFICATIONS,
+ AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
+
+ ops.add(new PackageOps(PACKAGE_3, UID_10_3, entries));
+
+ callStart(instance);
+
+ assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_1, PACKAGE_1));
+ assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_2, PACKAGE_2));
+ assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_3, PACKAGE_3));
+
+ assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_1, PACKAGE_1));
+ assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2));
+ assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_3, PACKAGE_3));
+ }
+
+ private void assertNoCallbacks(Listener l) throws Exception {
+ waitUntilMainHandlerDrain();
+ verify(l, times(0)).updateAllJobs();
+ verify(l, times(0)).updateJobsForUid(anyInt());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+ }
+
+ @Test
+ public void testPowerSaveListener() throws Exception {
+ final ForceAppStandbyTrackerTestable instance = newInstance();
+ callStart(instance);
+
+ ForceAppStandbyTracker.Listener l = mock(ForceAppStandbyTracker.Listener.class);
+ instance.addListener(l);
+
+ // Power save on.
+ mPowerSaveMode = true;
+ mPowerSaveObserver.accept(getPowerSaveState());
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(1)).updateAllJobs();
+ verify(l, times(0)).updateJobsForUid(anyInt());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ // Power save off.
+ mPowerSaveMode = false;
+ mPowerSaveObserver.accept(getPowerSaveState());
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(1)).updateAllJobs();
+ verify(l, times(0)).updateJobsForUid(anyInt());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(1)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ // Power save on.
+ mPowerSaveMode = true;
+ mPowerSaveObserver.accept(getPowerSaveState());
+
+ assertNoCallbacks(l);
+ }
+
+ @Test
+ public void testAllListeners() throws Exception {
+ final ForceAppStandbyTrackerTestable instance = newInstance();
+ callStart(instance);
+
+ ForceAppStandbyTracker.Listener l = mock(ForceAppStandbyTracker.Listener.class);
+ instance.addListener(l);
+
+ // -------------------------------------------------------------------------
+ // Test with apppops.
+
+ setAppOps(UID_10_2, PACKAGE_2, true);
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(0)).updateAllJobs();
+ verify(l, times(0)).updateJobsForUid(anyInt());
+ verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2));
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ setAppOps(UID_10_2, PACKAGE_2, false);
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(0)).updateAllJobs();
+ verify(l, times(0)).updateJobsForUid(anyInt());
+ verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2));
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(eq(UID_10_2), eq(PACKAGE_2));
+ reset(l);
+
+ setAppOps(UID_10_2, PACKAGE_2, false);
+
+ verify(l, times(0)).updateAllJobs();
+ verify(l, times(0)).updateJobsForUid(anyInt());
+ verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2));
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+
+ // Unrestrict while battery saver is on. Shouldn't fire.
+ mPowerSaveMode = true;
+ mPowerSaveObserver.accept(getPowerSaveState());
+
+ // Note toggling appops while BS is on will suppress unblockAlarmsForUidPackage().
+ setAppOps(UID_10_2, PACKAGE_2, true);
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(1)).updateAllJobs();
+ verify(l, times(0)).updateJobsForUid(anyInt());
+ verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2));
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ // Battery saver off.
+ mPowerSaveMode = false;
+ mPowerSaveObserver.accept(getPowerSaveState());
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(1)).updateAllJobs();
+ verify(l, times(0)).updateJobsForUid(anyInt());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(1)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ // -------------------------------------------------------------------------
+ // Tests with system/user/temp whitelist.
+
+ instance.setPowerSaveWhitelistAppIds(new int[] {UID_1, UID_2}, new int[] {});
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(1)).updateAllJobs();
+ verify(l, times(0)).updateJobsForUid(anyInt());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {});
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(1)).updateAllJobs();
+ verify(l, times(0)).updateJobsForUid(anyInt());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(1)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ // Update temp whitelist.
+ instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {UID_1, UID_3});
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(1)).updateAllJobs();
+ verify(l, times(0)).updateJobsForUid(anyInt());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {UID_3});
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(1)).updateAllJobs();
+ verify(l, times(0)).updateJobsForUid(anyInt());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ // Do the same thing with battery saver on. (Currently same callbacks are called.)
+ mPowerSaveMode = true;
+ mPowerSaveObserver.accept(getPowerSaveState());
+
+ instance.setPowerSaveWhitelistAppIds(new int[] {UID_1, UID_2}, new int[] {});
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(1)).updateAllJobs();
+ verify(l, times(0)).updateJobsForUid(anyInt());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {});
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(1)).updateAllJobs();
+ verify(l, times(0)).updateJobsForUid(anyInt());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(1)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ // Update temp whitelist.
+ instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {UID_1, UID_3});
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(1)).updateAllJobs();
+ verify(l, times(0)).updateJobsForUid(anyInt());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {UID_3});
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(1)).updateAllJobs();
+ verify(l, times(0)).updateJobsForUid(anyInt());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+
+ // -------------------------------------------------------------------------
+ // Tests with proc state changes.
+
+ // With battery save.
+ mPowerSaveMode = true;
+ mPowerSaveObserver.accept(getPowerSaveState());
+
+ mIUidObserver.onUidActive(UID_10_1);
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(0)).updateAllJobs();
+ verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ mIUidObserver.onUidGone(UID_10_1, true);
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(0)).updateAllJobs();
+ verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ mIUidObserver.onUidActive(UID_10_1);
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(0)).updateAllJobs();
+ verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ mIUidObserver.onUidIdle(UID_10_1, true);
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(0)).updateAllJobs();
+ verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ // Without battery save.
+ mPowerSaveMode = false;
+ mPowerSaveObserver.accept(getPowerSaveState());
+
+ mIUidObserver.onUidActive(UID_10_1);
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(0)).updateAllJobs();
+ verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ mIUidObserver.onUidGone(UID_10_1, true);
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(0)).updateAllJobs();
+ verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ mIUidObserver.onUidActive(UID_10_1);
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(0)).updateAllJobs();
+ verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
+ mIUidObserver.onUidIdle(UID_10_1, true);
+
+ waitUntilMainHandlerDrain();
+ verify(l, times(0)).updateAllJobs();
+ verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+ }
+
+ @Test
+ public void testUserRemoved() throws Exception {
+ final ForceAppStandbyTrackerTestable instance = newInstance();
+ callStart(instance);
+
+ mIUidObserver.onUidActive(UID_1);
+ mIUidObserver.onUidActive(UID_10_1);
+
+ setAppOps(UID_2, PACKAGE_2, true);
+ setAppOps(UID_10_2, PACKAGE_2, true);
+
+ assertTrue(instance.isInForeground(UID_1));
+ assertTrue(instance.isInForeground(UID_10_1));
+
+ assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_2, PACKAGE_2));
+ assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2));
+
+ final Intent intent = new Intent(Intent.ACTION_USER_REMOVED);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, 10);
+ mReceiver.onReceive(mMockContext, intent);
+
+ waitUntilMainHandlerDrain();
+
+ assertTrue(instance.isInForeground(UID_1));
+ assertFalse(instance.isInForeground(UID_10_1));
+
+ assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_2, PACKAGE_2));
+ assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2));
+ }
+
+ static int[] array(int... appIds) {
+ Arrays.sort(appIds);
+ return appIds;
+ }
+
+ private final Random mRandom = new Random();
+
+ int[] makeRandomArray() {
+ final ArrayList<Integer> list = new ArrayList<>();
+ for (int i = 0; i < 5; i++) {
+ if (mRandom.nextDouble() < 0.5) {
+ list.add(i);
+ }
+ }
+ return Arrays.stream(list.toArray(new Integer[list.size()]))
+ .mapToInt(Integer::intValue).toArray();
+ }
+
+ static boolean isAnyAppIdUnwhitelistedSlow(int[] prevArray, int[] newArray) {
+ Arrays.sort(newArray); // Just in case...
+ for (int p : prevArray) {
+ if (Arrays.binarySearch(newArray, p) < 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void checkAnyAppIdUnwhitelisted(int[] prevArray, int[] newArray, boolean expected) {
+ assertEquals("Input: " + Arrays.toString(prevArray) + " " + Arrays.toString(newArray),
+ expected, ForceAppStandbyTracker.isAnyAppIdUnwhitelisted(prevArray, newArray));
+
+ // Also test isAnyAppIdUnwhitelistedSlow.
+ assertEquals("Input: " + Arrays.toString(prevArray) + " " + Arrays.toString(newArray),
+ expected, isAnyAppIdUnwhitelistedSlow(prevArray, newArray));
+ }
+
+ @Test
+ public void isAnyAppIdUnwhitelisted() {
+ checkAnyAppIdUnwhitelisted(array(), array(), false);
+
+ checkAnyAppIdUnwhitelisted(array(1), array(), true);
+ checkAnyAppIdUnwhitelisted(array(1), array(1), false);
+ checkAnyAppIdUnwhitelisted(array(1), array(0, 1), false);
+ checkAnyAppIdUnwhitelisted(array(1), array(0, 1, 2), false);
+ checkAnyAppIdUnwhitelisted(array(1), array(0, 1, 2), false);
+
+ checkAnyAppIdUnwhitelisted(array(1, 2, 10), array(), true);
+ checkAnyAppIdUnwhitelisted(array(1, 2, 10), array(1, 2), true);
+ checkAnyAppIdUnwhitelisted(array(1, 2, 10), array(1, 2, 10), false);
+ checkAnyAppIdUnwhitelisted(array(1, 2, 10), array(2, 10), true);
+ checkAnyAppIdUnwhitelisted(array(1, 2, 10), array(0, 1, 2, 4, 3, 10), false);
+ checkAnyAppIdUnwhitelisted(array(1, 2, 10), array(0, 0, 1, 2, 10), false);
+
+ // Random test
+ int trueCount = 0;
+ final int count = 10000;
+ for (int i = 0; i < count; i++) {
+ final int[] array1 = makeRandomArray();
+ final int[] array2 = makeRandomArray();
+
+ final boolean expected = isAnyAppIdUnwhitelistedSlow(array1, array2);
+ final boolean actual = ForceAppStandbyTracker.isAnyAppIdUnwhitelisted(array1, array2);
+
+ assertEquals("Input: " + Arrays.toString(array1) + " " + Arrays.toString(array2),
+ expected, actual);
+ if (expected) {
+ trueCount++;
+ }
+ }
+
+ // Make sure makeRandomArray() didn't generate all same arrays by accident.
+ assertTrue(trueCount > 0);
+ assertTrue(trueCount < count);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 4078829..fbcccf0 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -37,7 +37,6 @@
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.Time.TIMEZONE_UTC;
-import static com.android.server.net.NetworkPolicyManagerService.MAX_PROC_STATE_SEQ_HISTORY;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
@@ -61,7 +60,6 @@
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -116,12 +114,10 @@
import android.util.TrustedTime;
import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.BroadcastInterceptingContext.FutureIntent;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.net.NetworkPolicyManagerService;
-import com.android.server.net.NetworkPolicyManagerService.ProcStateSeqHistory;
import libcore.io.IoUtils;
import libcore.io.Streams;
@@ -130,6 +126,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.MethodRule;
@@ -142,12 +139,10 @@
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
-import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
-import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -182,6 +177,7 @@
"com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner"
* </code></pre>
*/
+@Ignore
@RunWith(AndroidJUnit4.class)
@MediumTest
public class NetworkPolicyManagerServiceTest {
@@ -191,8 +187,6 @@
private static final String TEST_IFACE = "test0";
private static final String TEST_SSID = "AndroidAP";
- private static final String LINE_SEPARATOR = System.getProperty("line.separator");
-
private static NetworkTemplate sTemplateWifi = NetworkTemplate.buildTemplateWifi(TEST_SSID);
/**
@@ -1109,14 +1103,6 @@
final long procStateSeq = 222;
callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq);
verify(mActivityManagerInternal).notifyNetworkPolicyRulesUpdated(UID_A, procStateSeq);
-
- final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- final IndentingPrintWriter writer = new IndentingPrintWriter(
- new PrintWriter(outputStream), " ");
- mService.mObservedHistory.dumpUL(writer);
- writer.flush();
- assertEquals(ProcStateSeqHistory.getString(UID_A, procStateSeq),
- outputStream.toString().trim());
}
private void callOnUidStateChanged(int uid, int procState, long procStateSeq)
@@ -1129,59 +1115,6 @@
latch.await(2, TimeUnit.SECONDS);
}
- @Test
- public void testProcStateHistory() {
- // Verify dump works correctly with no elements added.
- verifyProcStateHistoryDump(0);
-
- // Add items upto half of the max capacity and verify that dump works correctly.
- verifyProcStateHistoryDump(MAX_PROC_STATE_SEQ_HISTORY / 2);
-
- // Add items upto the max capacity and verify that dump works correctly.
- verifyProcStateHistoryDump(MAX_PROC_STATE_SEQ_HISTORY);
-
- // Add more items than max capacity and verify that dump works correctly.
- verifyProcStateHistoryDump(MAX_PROC_STATE_SEQ_HISTORY + MAX_PROC_STATE_SEQ_HISTORY / 2);
-
- }
-
- private void verifyProcStateHistoryDump(int count) {
- final ProcStateSeqHistory history = new ProcStateSeqHistory(MAX_PROC_STATE_SEQ_HISTORY);
- final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- final IndentingPrintWriter writer = new IndentingPrintWriter(
- new PrintWriter(outputStream), " ");
-
- if (count == 0) {
- // Verify with no uid info written to history.
- history.dumpUL(writer);
- writer.flush();
- assertEquals("When no uid info is there, dump should contain NONE",
- "NONE", outputStream.toString().trim());
- return;
- }
-
- int uid = 111;
- long procStateSeq = 222;
- // Add count items and verify dump works correctly.
- for (int i = 0; i < count; ++i) {
- uid++;
- procStateSeq++;
- history.addProcStateSeqUL(uid, procStateSeq);
- }
- history.dumpUL(writer);
- writer.flush();
- final String[] uidsDump = outputStream.toString().split(LINE_SEPARATOR);
- // Dump will have at most MAX_PROC_STATE_SEQ_HISTORY items.
- final int expectedCount = (count < MAX_PROC_STATE_SEQ_HISTORY)
- ? count : MAX_PROC_STATE_SEQ_HISTORY;
- assertEquals(expectedCount, uidsDump.length);
- for (int i = 0; i < expectedCount; ++i) {
- assertEquals(ProcStateSeqHistory.getString(uid, procStateSeq), uidsDump[i]);
- uid--;
- procStateSeq--;
- }
- }
-
private void assertCycleDayAsExpected(PersistableBundle config, int carrierCycleDay,
boolean expectValid) {
config.putInt(KEY_MONTHLY_DATA_CYCLE_DAY_INT, carrierCycleDay);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java
new file mode 100644
index 0000000..7160d7f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java
@@ -0,0 +1,91 @@
+/*
+ * 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.am;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
+import com.android.server.am.ActivityStarter.Factory;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.times;
+
+import java.util.Random;
+
+/**
+ * Tests for the {@link ActivityStartController} class.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:ActivityStartControllerTests
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ActivityStartControllerTests extends ActivityTestsBase {
+ private ActivityManagerService mService;
+ private ActivityStartController mController;
+ private Factory mFactory;
+ private ActivityStarter mStarter;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mService = createActivityManagerService();
+ mFactory = mock(Factory.class);
+ mController = new ActivityStartController(mService, mService.mStackSupervisor, mFactory);
+ mStarter = spy(new ActivityStarter(mController, mService, mService.mStackSupervisor,
+ mock(ActivityStartInterceptor.class)));
+ doReturn(mStarter).when(mFactory).obtainStarter();
+ }
+
+ /**
+ * Ensures that pending launches are processed.
+ */
+ @Test
+ @Presubmit
+ public void testPendingActivityLaunches() {
+ final Random random = new Random();
+
+ final ActivityRecord activity = new ActivityBuilder(mService).build();
+ final ActivityRecord source = new ActivityBuilder(mService).build();
+ final int startFlags = random.nextInt();
+ final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final ProcessRecord process= new ProcessRecord(null, mService.mContext.getApplicationInfo(),
+ "name", 12345);
+
+ mController.addPendingActivityLaunch(
+ new PendingActivityLaunch(activity, source, startFlags, stack, process));
+ final boolean resume = random.nextBoolean();
+ mController.doPendingActivityLaunches(resume);
+
+ verify(mStarter, times(1)).startResolvedActivity(eq(activity), eq(source), eq(null),
+ eq(null), eq(startFlags), eq(resume), eq(null), eq(null), eq(null));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
index b4919b6..e8194dd 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
@@ -65,10 +65,10 @@
import com.android.internal.os.BatteryStatsImpl;
/**
- * Tests for the {@link ActivityStack} class.
+ * Tests for the {@link ActivityStarter} class.
*
* Build/Install/Run:
- * bit FrameworksServicesTests:com.android.server.am.ActivityStarterTests
+ * atest FrameworksServicesTests:ActivityStarterTests
*/
@SmallTest
@Presubmit
@@ -76,7 +76,7 @@
public class ActivityStarterTests extends ActivityTestsBase {
private ActivityManagerService mService;
private ActivityStarter mStarter;
- private IPackageManager mPackageManager;
+ private ActivityStartController mController;
private static final int PRECONDITION_NO_CALLER_APP = 1;
private static final int PRECONDITION_NO_INTENT_COMPONENT = 1 << 1;
@@ -94,7 +94,9 @@
public void setUp() throws Exception {
super.setUp();
mService = createActivityManagerService();
- mStarter = new ActivityStarter(mService);
+ mController = mock(ActivityStartController.class);
+ mStarter = new ActivityStarter(mController, mService, mService.mStackSupervisor,
+ mock(ActivityStartInterceptor.class));
}
@Test
@@ -164,10 +166,9 @@
* 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})
* and the launch flags specified in the intent. The method constructs a call to
- * {@link ActivityStarter#startActivityLocked} based on these preconditions and ensures the
- * result matches the expected. It is important to note that the method also checks side effects
- * of the start, such as ensuring {@link ActivityOptions#abort()} is called in the relevant
- * scenarios.
+ * {@link ActivityStarter#execute} based on these preconditions and ensures the result matches
+ * the expected. It is important to note that the method also checks side effects of the start,
+ * such as ensuring {@link ActivityOptions#abort()} is called in the relevant scenarios.
* @param preconditions A bitmask representing the preconditions for the launch
* @param launchFlags The launch flags to be provided by the launch {@link Intent}.
* @param expectedResult The expected result from the launch.
@@ -176,8 +177,10 @@
int expectedResult) {
final ActivityManagerService service = createActivityManagerService();
final IPackageManager packageManager = mock(IPackageManager.class);
- final ActivityStarter starter = new ActivityStarter(service);
+ final ActivityStartController controller = mock(ActivityStartController.class);
+ final ActivityStarter starter = new ActivityStarter(controller, service,
+ service.mStackSupervisor, mock(ActivityStartInterceptor.class));
final IApplicationThread caller = mock(IApplicationThread.class);
// If no caller app, return {@code null} {@link ProcessRecord}.
@@ -250,14 +253,13 @@
final int requestCode = containsConditions(preconditions, PRECONDITION_REQUEST_CODE)
? 1 : 0;
- final int result = starter.startActivityLocked(caller, intent,
- null /*ephemeralIntent*/, null /*resolvedType*/, aInfo, null /*rInfo*/,
- null /*voiceSession*/, null /*voiceInteractor*/, resultTo,
- null /*resultWho*/, requestCode, 0 /*callingPid*/, 0 /*callingUid*/,
- null /*callingPackage*/, 0 /*realCallingPid*/, 0 /*realCallingUid*/,
- 0 /*startFlags*/, null /*options*/, false /*ignoreTargetSecurity*/,
- false /*componentSpecified*/, null /*outActivity*/,
- null /*inTask*/, "testLaunchActivityPermissionDenied");
+ final int result = starter.setCaller(caller)
+ .setIntent(intent)
+ .setActivityInfo(aInfo)
+ .setResultTo(resultTo)
+ .setRequestCode(requestCode)
+ .setReason("testLaunchActivityPermissionDenied")
+ .execute();
// In some cases the expected result internally is different than the published result. We
// must use ActivityStarter#getExternalResult to translate.
@@ -265,16 +267,25 @@
// Ensure that {@link ActivityOptions} are aborted with unsuccessful result.
if (expectedResult != START_SUCCESS) {
+ final ActivityStarter optionStarter = new ActivityStarter(mController, mService,
+ mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
final ActivityOptions options = spy(ActivityOptions.makeBasic());
- final int optionResult = starter.startActivityLocked(caller, intent,
- null /*ephemeralIntent*/, null /*resolvedType*/, aInfo, null /*rInfo*/,
- null /*voiceSession*/, null /*voiceInteractor*/, resultTo,
- null /*resultWho*/, requestCode, 0 /*callingPid*/, 0 /*callingUid*/,
- null /*callingPackage*/, 0 /*realCallingPid*/, 0 /*realCallingUid*/,
- 0 /*startFlags*/, options /*options*/, false /*ignoreTargetSecurity*/,
- false /*componentSpecified*/, null /*outActivity*/,
- null /*inTask*/, "testLaunchActivityPermissionDenied");
+
+ final int optionResult = optionStarter.setCaller(caller)
+ .setIntent(intent)
+ .setActivityInfo(aInfo)
+ .setResultTo(resultTo)
+ .setRequestCode(requestCode)
+ .setReason("testLaunchActivityPermissionDenied")
+ .setActivityOptions(options)
+ .execute();
verify(options, times(1)).abort();
}
}
+
+// TODO(b/69270257): Add test to verify task layout is passed additional data such as activity and
+// source.
+// @Test
+// public void testCreateTaskLayout() {
+// }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 2fffb89..d74d994 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -191,6 +191,7 @@
private String mPackage;
private int mFlags = 0;
private int mTaskId = 0;
+ private int mUserId = 0;
private IVoiceInteractionSession mVoiceSession;
private ActivityStack mStack;
@@ -224,6 +225,11 @@
return this;
}
+ TaskBuilder setUserId(int userId) {
+ mUserId = userId;
+ return this;
+ }
+
TaskBuilder setStack(ActivityStack stack) {
mStack = stack;
return this;
@@ -245,10 +251,12 @@
final TaskRecord task = new TaskRecord(mSupervisor.mService, mTaskId, aInfo,
intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/);
+ task.userId = mUserId;
mSupervisor.setFocusStackUnchecked("test", mStack);
mStack.addTask(task, true, "creating test task");
task.setStack(mStack);
task.setWindowContainerController(mock(TaskWindowContainerController.class));
+ task.touchActiveTime();
return task;
}
diff --git a/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java b/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java
index 1adfb67..d2ae22b 100644
--- a/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java
@@ -30,6 +30,7 @@
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NONE;
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS;
import static android.os.Process.SYSTEM_UID;
+import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT;
import static com.android.server.am.LockTaskController.STATUS_BAR_MASK_LOCKED;
import static com.android.server.am.LockTaskController.STATUS_BAR_MASK_PINNED;
@@ -53,6 +54,7 @@
import android.provider.Settings;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
+import android.telecom.TelecomManager;
import android.util.Pair;
import com.android.internal.statusbar.IStatusBarService;
@@ -90,6 +92,8 @@
@Mock private LockPatternUtils mLockPatternUtils;
@Mock private LockTaskNotify mLockTaskNotify;
@Mock private StatusBarManagerInternal mStatusBarManagerInternal;
+ @Mock private TelecomManager mTelecomManager;
+ @Mock private RecentTasks mRecentTasks;
private LockTaskController mLockTaskController;
private Context mContext;
@@ -110,12 +114,14 @@
Looper.prepare();
}
+ mSupervisor.mRecentTasks = mRecentTasks;
+
mLockTaskController = new LockTaskController(mContext, mSupervisor,
new ImmediatelyExecuteHandler());
-
mLockTaskController.setWindowManager(mWindowManager);
mLockTaskController.mStatusBarService = mStatusBarService;
mLockTaskController.mDevicePolicyManager = mDevicePolicyManager;
+ mLockTaskController.mTelecomManager = mTelecomManager;
mLockTaskController.mLockPatternUtils = mLockPatternUtils;
mLockTaskController.mLockTaskNotify = mLockTaskNotify;
@@ -207,7 +213,7 @@
@Test
public void testLockTaskViolation() throws Exception {
- // GIVEN one task records with whitelisted auth that is in lock task mode
+ // GIVEN one task record with whitelisted auth that is in lock task mode
TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
@@ -232,6 +238,38 @@
}
@Test
+ public void testLockTaskViolation_emergencyCall() throws Exception {
+ // GIVEN one task record with whitelisted auth that is in lock task mode
+ TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+ mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
+
+ // GIVEN tasks necessary for emergency calling
+ TaskRecord keypad = getTaskRecord(new Intent().setComponent(EMERGENCY_DIALER_COMPONENT),
+ TaskRecord.LOCK_TASK_AUTH_PINNABLE);
+ TaskRecord callAction = getTaskRecord(new Intent(Intent.ACTION_CALL_EMERGENCY),
+ TaskRecord.LOCK_TASK_AUTH_PINNABLE);
+ TaskRecord dialer = getTaskRecord("com.example.dialer", TaskRecord.LOCK_TASK_AUTH_PINNABLE);
+ when(mTelecomManager.getSystemDialerPackage())
+ .thenReturn(dialer.intent.getComponent().getPackageName());
+
+ // GIVEN keyguard is allowed for lock task mode
+ mLockTaskController.updateLockTaskFeatures(TEST_USER_ID, LOCK_TASK_FEATURE_KEYGUARD);
+
+ // THEN the above tasks should all be allowed
+ assertFalse(mLockTaskController.isLockTaskModeViolation(keypad));
+ assertFalse(mLockTaskController.isLockTaskModeViolation(callAction));
+ assertFalse(mLockTaskController.isLockTaskModeViolation(dialer));
+
+ // GIVEN keyguard is disallowed for lock task mode (default)
+ mLockTaskController.updateLockTaskFeatures(TEST_USER_ID, LOCK_TASK_FEATURE_NONE);
+
+ // THEN the above tasks should all be blocked
+ assertTrue(mLockTaskController.isLockTaskModeViolation(keypad));
+ assertTrue(mLockTaskController.isLockTaskModeViolation(callAction));
+ assertTrue(mLockTaskController.isLockTaskModeViolation(dialer));
+ }
+
+ @Test
public void testStopLockTaskMode() throws Exception {
// GIVEN one task record with whitelisted auth that is in lock task mode
TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
@@ -566,10 +604,15 @@
}
private TaskRecord getTaskRecord(String pkg, int lockTaskAuth) {
+ final Intent intent = new Intent()
+ .setComponent(ComponentName.createRelative(pkg, TEST_CLASS_NAME));
+ return getTaskRecord(intent, lockTaskAuth);
+ }
+
+ private TaskRecord getTaskRecord(Intent intent, int lockTaskAuth) {
TaskRecord tr = mock(TaskRecord.class);
tr.mLockTaskAuth = lockTaskAuth;
- tr.intent = new Intent()
- .setComponent(ComponentName.createRelative(pkg, TEST_CLASS_NAME));
+ tr.intent = intent;
tr.userId = TEST_USER_ID;
return tr;
}
@@ -601,6 +644,8 @@
eq(mContext.getPackageName()));
verify(mStatusBarService).disable2(eq(statusBarMask2), any(IBinder.class),
eq(mContext.getPackageName()));
+ // THEN recents should have been notified
+ verify(mRecentTasks).onLockTaskModeStateChanged(anyInt(), eq(TEST_USER_ID));
// THEN the DO/PO should be informed about the operation
verify(mDevicePolicyManager).notifyLockTaskModeChanged(true, TEST_PACKAGE_NAME,
TEST_USER_ID);
diff --git a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
index afece5d..0d03863 100644
--- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
@@ -23,6 +23,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+import static android.view.Display.DEFAULT_DISPLAY;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -30,6 +31,8 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static java.lang.Integer.MAX_VALUE;
@@ -42,6 +45,7 @@
import android.content.pm.UserInfo;
import android.graphics.Rect;
import android.os.Bundle;
+import android.os.Debug;
import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -64,6 +68,7 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Random;
import java.util.Set;
/**
@@ -78,17 +83,19 @@
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 final ComponentName MY_COMPONENT = new ComponentName(
- RecentTasksTest.class.getPackage().getName(), RecentTasksTest.class.getName());
private static int LAST_TASK_ID = 1;
+ private static int LAST_STACK_ID = 1;
private static int INVALID_STACK_ID = 999;
private Context mContext = InstrumentationRegistry.getContext();
private ActivityManagerService mService;
+ private ActivityDisplay mDisplay;
+ private ActivityDisplay mOtherDisplay;
private ActivityStack mStack;
+ private ActivityStack mHomeStack;
private TestTaskPersister mTaskPersister;
- private RecentTasks mRecentTasks;
- private RunningTasks mRunningTasks;
+ private TestRecentTasks mRecentTasks;
+ private TestRunningTasks mRunningTasks;
private static ArrayList<TaskRecord> mTasks = new ArrayList<>();
private static ArrayList<TaskRecord> mSameDocumentTasks = new ArrayList<>();
@@ -133,22 +140,25 @@
mTaskPersister = new TestTaskPersister(mContext.getFilesDir());
mService = setupActivityManagerService(new MyTestActivityManagerService(mContext));
- mRecentTasks = mService.getRecentTasks();
+ mRecentTasks = (TestRecentTasks) mService.getRecentTasks();
mRecentTasks.loadParametersFromResources(mContext.getResources());
+ mHomeStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ ((MyTestActivityStackSupervisor) mService.mStackSupervisor).setHomeStack(mHomeStack);
mCallbacksRecorder = new CallbacksRecorder();
mRecentTasks.registerCallback(mCallbacksRecorder);
QUIET_USER_INFO.flags = UserInfo.FLAG_MANAGED_PROFILE | UserInfo.FLAG_QUIET_MODE;
- mTasks.add(createTask(".Task1"));
- mTasks.add(createTask(".Task2"));
- mTasks.add(createTask(".Task3"));
- mTasks.add(createTask(".Task4"));
- mTasks.add(createTask(".Task5"));
+ mTasks.add(createTaskBuilder(".Task1").build());
+ mTasks.add(createTaskBuilder(".Task2").build());
+ mTasks.add(createTaskBuilder(".Task3").build());
+ mTasks.add(createTaskBuilder(".Task4").build());
+ mTasks.add(createTaskBuilder(".Task5").build());
- mSameDocumentTasks.add(createDocumentTask(".DocumentTask1", null /* affinity */));
- mSameDocumentTasks.add(createDocumentTask(".DocumentTask1", null /* affinity */));
+ mSameDocumentTasks.add(createDocumentTask(".DocumentTask1"));
+ mSameDocumentTasks.add(createDocumentTask(".DocumentTask1"));
}
@Test
@@ -172,9 +182,9 @@
mCallbacksRecorder.clear();
// Add a task which will trigger the trimming of another
- TaskRecord documentTask1 = createDocumentTask(".DocumentTask1", null /* affinity */);
+ TaskRecord documentTask1 = createDocumentTask(".DocumentTask1");
documentTask1.maxRecents = 1;
- TaskRecord documentTask2 = createDocumentTask(".DocumentTask1", null /* affinity */);
+ TaskRecord documentTask2 = createDocumentTask(".DocumentTask1");
mRecentTasks.add(documentTask1);
mRecentTasks.add(documentTask2);
assertTrue(mCallbacksRecorder.added.contains(documentTask1));
@@ -194,13 +204,15 @@
@Test
public void testUsersTasks() throws Exception {
+ mRecentTasks.setOnlyTestVisibleRange();
+
// Setup some tasks for the users
mTaskPersister.userTaskIdsOverride = new SparseBooleanArray();
mTaskPersister.userTaskIdsOverride.put(1, true);
mTaskPersister.userTaskIdsOverride.put(2, true);
mTaskPersister.userTasksOverride = new ArrayList<>();
- mTaskPersister.userTasksOverride.add(createTask(".UserTask1"));
- mTaskPersister.userTasksOverride.add(createTask(".UserTask2"));
+ mTaskPersister.userTasksOverride.add(createTaskBuilder(".UserTask1").build());
+ mTaskPersister.userTasksOverride.add(createTaskBuilder(".UserTask2").build());
// Assert no user tasks are initially loaded
assertTrue(mRecentTasks.usersWithRecentsLoadedLocked().length == 0);
@@ -235,6 +247,20 @@
@Test
public void testOrderedIteration() throws Exception {
+ mRecentTasks.setOnlyTestVisibleRange();
+ TaskRecord task1 = createTaskBuilder(".Task1").build();
+ task1.lastActiveTime = new Random().nextInt();
+ TaskRecord task2 = createTaskBuilder(".Task1").build();
+ task2.lastActiveTime = new Random().nextInt();
+ TaskRecord task3 = createTaskBuilder(".Task1").build();
+ task3.lastActiveTime = new Random().nextInt();
+ TaskRecord task4 = createTaskBuilder(".Task1").build();
+ task4.lastActiveTime = new Random().nextInt();
+ mRecentTasks.add(task1);
+ mRecentTasks.add(task2);
+ mRecentTasks.add(task3);
+ mRecentTasks.add(task4);
+
MutableLong prevLastActiveTime = new MutableLong(0);
final ArrayList<TaskRecord> tasks = mRecentTasks.getRawTasks();
for (int i = 0; i < tasks.size(); i++) {
@@ -246,6 +272,8 @@
@Test
public void testTrimToGlobalMaxNumRecents() throws Exception {
+ mRecentTasks.setOnlyTestVisibleRange();
+
// Limit the global maximum number of recent tasks to a fixed size
mRecentTasks.setGlobalMaxNumTasks(2 /* globalMaxNumTasks */);
@@ -260,8 +288,9 @@
@Test
public void testTrimQuietProfileTasks() throws Exception {
- TaskRecord qt1 = createTask(".QuietTask1", TEST_QUIET_USER_ID);
- TaskRecord qt2 = createTask(".QuietTask2", TEST_QUIET_USER_ID);
+ mRecentTasks.setOnlyTestVisibleRange();
+ TaskRecord qt1 = createTaskBuilder(".QuietTask1").setUserId(TEST_QUIET_USER_ID).build();
+ TaskRecord qt2 = createTaskBuilder(".QuietTask2").setUserId(TEST_QUIET_USER_ID).build();
mRecentTasks.add(qt1);
mRecentTasks.add(qt2);
@@ -274,16 +303,17 @@
@Test
public void testSessionDuration() throws Exception {
+ mRecentTasks.setOnlyTestVisibleRange();
mRecentTasks.setParameters(-1 /* min */, -1 /* max */, 50 /* ms */);
- TaskRecord t1 = createTask(".Task1");
+ TaskRecord t1 = createTaskBuilder(".Task1").build();
t1.touchActiveTime();
mRecentTasks.add(t1);
// Force a small sleep just beyond the session duration
SystemClock.sleep(75);
- TaskRecord t2 = createTask(".Task2");
+ TaskRecord t2 = createTaskBuilder(".Task2").build();
t2.touchActiveTime();
mRecentTasks.add(t2);
@@ -293,12 +323,15 @@
@Test
public void testVisibleTasks_excludedFromRecents() throws Exception {
+ mRecentTasks.setOnlyTestVisibleRange();
mRecentTasks.setParameters(-1 /* min */, 4 /* max */, -1 /* ms */);
- TaskRecord excludedTask1 = createTask(".ExcludedTask1", FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS,
- TEST_USER_0_ID);
- TaskRecord excludedTask2 = createTask(".ExcludedTask2", FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS,
- TEST_USER_0_ID);
+ TaskRecord excludedTask1 = createTaskBuilder(".ExcludedTask1")
+ .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+ .build();
+ TaskRecord excludedTask2 = createTaskBuilder(".ExcludedTask2")
+ .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+ .build();
mRecentTasks.add(excludedTask1);
mRecentTasks.add(mTasks.get(0));
@@ -312,6 +345,7 @@
@Test
public void testVisibleTasks_minNum() throws Exception {
+ mRecentTasks.setOnlyTestVisibleRange();
mRecentTasks.setParameters(5 /* min */, -1 /* max */, 25 /* ms */);
for (int i = 0; i < 4; i++) {
@@ -327,12 +361,12 @@
mRecentTasks.add(mTasks.get(4));
// Ensure that there are a minimum number of tasks regardless of session length
- assertTrue(mCallbacksRecorder.trimmed.isEmpty());
- assertTrue(mCallbacksRecorder.removed.isEmpty());
+ assertNoTasksTrimmed();
}
@Test
public void testVisibleTasks_maxNum() throws Exception {
+ mRecentTasks.setOnlyTestVisibleRange();
mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */);
for (int i = 0; i < 5; i++) {
@@ -346,16 +380,78 @@
}
@Test
+ public void testBackStackTasks_expectNoTrim() throws Exception {
+ mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
+
+ final MyTestActivityStackSupervisor supervisor =
+ (MyTestActivityStackSupervisor) mService.mStackSupervisor;
+ final ActivityStack homeStack = new MyTestActivityStack(mDisplay, supervisor);
+ final ActivityStack aboveHomeStack = new MyTestActivityStack(mDisplay, supervisor);
+ supervisor.setHomeStack(homeStack);
+
+ // 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
+ mRecentTasks.add(createTaskBuilder(".HomeTask1").setStack(homeStack).build());
+ mRecentTasks.add(createTaskBuilder(".Task1").setStack(aboveHomeStack).build());
+ mRecentTasks.add(createTaskBuilder(".Task2").setStack(aboveHomeStack).build());
+ mRecentTasks.add(createTaskBuilder(".Task3").setStack(aboveHomeStack).build());
+
+ assertNoTasksTrimmed();
+ }
+
+ @Test
+ public void testBehindHomeStackTasks_expectTaskTrimmed() throws Exception {
+ mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
+
+ final MyTestActivityStackSupervisor supervisor =
+ (MyTestActivityStackSupervisor) mService.mStackSupervisor;
+ final ActivityStack behindHomeStack = new MyTestActivityStack(mDisplay, supervisor);
+ final ActivityStack homeStack = new MyTestActivityStack(mDisplay, supervisor);
+ final ActivityStack aboveHomeStack = new MyTestActivityStack(mDisplay, supervisor);
+ supervisor.setHomeStack(homeStack);
+
+ // 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
+ final TaskRecord behindHomeTask = createTaskBuilder(".Task1")
+ .setStack(behindHomeStack)
+ .build();
+ mRecentTasks.add(behindHomeTask);
+ mRecentTasks.add(createTaskBuilder(".HomeTask1").setStack(homeStack).build());
+ mRecentTasks.add(createTaskBuilder(".Task2").setStack(aboveHomeStack).build());
+
+ assertTrimmed(behindHomeTask);
+ }
+
+ @Test
+ public void testOtherDisplayTasks_expectNoTrim() throws Exception {
+ mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
+
+ final MyTestActivityStackSupervisor supervisor =
+ (MyTestActivityStackSupervisor) mService.mStackSupervisor;
+ final ActivityStack homeStack = new MyTestActivityStack(mDisplay, supervisor);
+ final ActivityStack otherDisplayStack = new MyTestActivityStack(mOtherDisplay, supervisor);
+ supervisor.setHomeStack(homeStack);
+
+ // Add a number of tasks (beyond the max) on each display, ensure that the tasks are not
+ // removed
+ mRecentTasks.add(createTaskBuilder(".HomeTask1").setStack(homeStack).build());
+ mRecentTasks.add(createTaskBuilder(".Task1").setStack(otherDisplayStack).build());
+ mRecentTasks.add(createTaskBuilder(".Task2").setStack(otherDisplayStack).build());
+ mRecentTasks.add(createTaskBuilder(".HomeTask2").setStack(homeStack).build());
+
+ assertNoTasksTrimmed();
+ }
+
+ @Test
public void testNotRecentsComponent_denyApiAccess() throws Exception {
doReturn(PackageManager.PERMISSION_DENIED).when(mService).checkPermission(anyString(),
anyInt(), anyInt());
// Expect the following methods to fail due to recents component not being set
- ((TestRecentTasks) mRecentTasks).setIsCallerRecentsOverride(
- TestRecentTasks.DENY_THROW_SECURITY_EXCEPTION);
+ mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.DENY_THROW_SECURITY_EXCEPTION);
testRecentTasksApis(false /* expectNoSecurityException */);
// Don't throw for the following tests
- ((TestRecentTasks) mRecentTasks).setIsCallerRecentsOverride(TestRecentTasks.DENY);
+ mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.DENY);
testGetTasksApis(false /* expectNoSecurityException */);
}
@@ -365,7 +461,7 @@
anyInt(), anyInt());
// Set the recents component and ensure that the following calls do not fail
- ((TestRecentTasks) mRecentTasks).setIsCallerRecentsOverride(TestRecentTasks.GRANT);
+ mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.GRANT);
testRecentTasksApis(true /* expectNoSecurityException */);
testGetTasksApis(true /* expectNoSecurityException */);
}
@@ -383,7 +479,7 @@
() -> mService.moveTaskToStack(0, INVALID_STACK_ID, true));
assertSecurityException(expectCallable,
() -> mService.setTaskWindowingModeSplitScreenPrimary(0,
- SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, true, true, new Rect()));
+ SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, true, true, new Rect(), true));
assertSecurityException(expectCallable, () -> mService.dismissSplitScreenMode(true));
assertSecurityException(expectCallable, () -> mService.dismissPip(true, 0));
assertSecurityException(expectCallable,
@@ -436,38 +532,27 @@
mService.getRecentTasks(MAX_VALUE, 0, TEST_USER_0_ID);
mService.getTasks(MAX_VALUE);
if (expectCallable) {
- assertTrue(((TestRecentTasks) mRecentTasks).mLastAllowed);
- assertTrue(((TestRunningTasks) mRunningTasks).mLastAllowed);
+ assertTrue(mRecentTasks.lastAllowed);
+ assertTrue(mRunningTasks.lastAllowed);
} else {
- assertFalse(((TestRecentTasks) mRecentTasks).mLastAllowed);
- assertFalse(((TestRunningTasks) mRunningTasks).mLastAllowed);
+ assertFalse(mRecentTasks.lastAllowed);
+ assertFalse(mRunningTasks.lastAllowed);
}
}
- private ComponentName createComponent(String className) {
- return new ComponentName(mContext.getPackageName(), className);
+ private TaskBuilder createTaskBuilder(String className) {
+ return new TaskBuilder(mService.mStackSupervisor)
+ .setComponent(new ComponentName(mContext.getPackageName(), className))
+ .setStack(mStack)
+ .setTaskId(LAST_TASK_ID++)
+ .setUserId(TEST_USER_0_ID);
}
- private TaskRecord createTask(String className) {
- return createTask(className, TEST_USER_0_ID);
- }
-
- private TaskRecord createTask(String className, int userId) {
- return createTask(className, 0 /* flags */, userId);
- }
-
- private TaskRecord createTask(String className, int flags, int userId) {
- TaskRecord task = new TaskBuilder(mService.mStackSupervisor)
- .setComponent(createComponent(className))
- .setStack(mStack).setFlags(flags).setTaskId(LAST_TASK_ID++).build();
- task.userId = userId;
- task.touchActiveTime();
- return task;
- }
-
- private TaskRecord createDocumentTask(String className, String affinity) {
- TaskRecord task = createTask(className, FLAG_ACTIVITY_NEW_DOCUMENT, TEST_USER_0_ID);
- task.affinity = affinity;
+ private TaskRecord createDocumentTask(String className) {
+ TaskRecord task = createTaskBuilder(className)
+ .setFlags(FLAG_ACTIVITY_NEW_DOCUMENT)
+ .build();
+ task.affinity = null;
return task;
}
@@ -476,6 +561,10 @@
return Arrays.binarySearch(userIds, targetUserId) >= 0;
}
+ private void assertNoTasksTrimmed() {
+ assertTrimmed();
+ }
+
private void assertTrimmed(TaskRecord... tasks) {
final ArrayList<TaskRecord> trimmed = mCallbacksRecorder.trimmed;
final ArrayList<TaskRecord> removed = mCallbacksRecorder.removed;
@@ -532,10 +621,41 @@
}
@Override
+ public void initialize() {
+ super.initialize();
+ mDisplay = new ActivityDisplay(this, DEFAULT_DISPLAY);
+ mOtherDisplay = new ActivityDisplay(this, DEFAULT_DISPLAY);
+ attachDisplay(mOtherDisplay);
+ attachDisplay(mDisplay);
+ }
+
+ @Override
RunningTasks createRunningTasks() {
mRunningTasks = new TestRunningTasks();
return mRunningTasks;
}
+
+ void setHomeStack(ActivityStack stack) {
+ mHomeStack = stack;
+ }
+ }
+
+ private class MyTestActivityStack extends TestActivityStack {
+ private ActivityDisplay mDisplay = null;
+
+ MyTestActivityStack(ActivityDisplay display, ActivityStackSupervisor supervisor) {
+ super(display, LAST_STACK_ID++, supervisor, WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, true);
+ mDisplay = display;
+ }
+
+ @Override
+ ActivityDisplay getDisplay() {
+ if (mDisplay != null) {
+ return mDisplay;
+ }
+ return super.getDisplay();
+ }
}
private static class CallbacksRecorder implements Callbacks {
@@ -564,7 +684,6 @@
}
private static class TestTaskPersister extends TaskPersister {
-
SparseBooleanArray userTaskIdsOverride;
ArrayList<TaskRecord> userTasksOverride;
@@ -595,8 +714,10 @@
static final int DENY_THROW_SECURITY_EXCEPTION = 2;
private boolean mOverrideIsCallerRecents;
+ private boolean mIsTrimmableOverride;
private int mIsCallerRecentsPolicy;
- boolean mLastAllowed;
+
+ boolean lastAllowed;
TestRecentTasks(ActivityManagerService service, TaskPersister taskPersister,
UserController userController) {
@@ -623,26 +744,41 @@
mIsCallerRecentsPolicy = policy;
}
+ /**
+ * To simplify the setup for some tests, the caller can request that we only rely on the
+ * visible range test to determine what is trimmable. In this case, we don't try to
+ * use the stack order to determine additionally if the task is trimmable when it is not
+ * in the visible range.
+ */
+ void setOnlyTestVisibleRange() {
+ mIsTrimmableOverride = true;
+ }
+
@Override
ParceledListSlice<RecentTaskInfo> getRecentTasks(int maxNum, int flags,
boolean getTasksAllowed,
boolean getDetailedTasks, int userId, int callingUid) {
- mLastAllowed = getTasksAllowed;
+ lastAllowed = getTasksAllowed;
return super.getRecentTasks(maxNum, flags, getTasksAllowed, getDetailedTasks, userId,
callingUid);
}
+
+ @Override
+ protected boolean isTrimmable(TaskRecord task) {
+ return mIsTrimmableOverride || super.isTrimmable(task);
+ }
}
private static class TestRunningTasks extends RunningTasks {
- boolean mLastAllowed;
+ boolean lastAllowed;
@Override
void getTasks(int maxNum, List<RunningTaskInfo> list, int ignoreActivityType,
int ignoreWindowingMode, SparseArray<ActivityDisplay> activityDisplays,
int callingUid, boolean allowed) {
- mLastAllowed = allowed;
+ lastAllowed = allowed;
super.getTasks(maxNum, list, ignoreActivityType, ignoreWindowingMode, activityDisplays,
callingUid, allowed);
}
}
-}
\ No newline at end of file
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java b/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java
new file mode 100644
index 0000000..5520bd7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java
@@ -0,0 +1,125 @@
+/*
+ * 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.am;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.platform.test.annotations.Presubmit;
+import android.service.voice.IVoiceInteractionSession;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.app.IVoiceInteractor;
+import com.android.server.am.TaskRecord.TaskRecordFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * Tests for exercising {@link TaskRecord}.
+ *
+ * Build/Install/Run:
+ * bit FrameworksServicesTests:com.android.server.am.TaskRecordTests
+ */
+@MediumTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class TaskRecordTests {
+
+ @Before
+ public void setUp() throws Exception {
+ TaskRecord.setTaskRecordFactory(null);
+ }
+
+ @Test
+ public void testDefaultTaskFactoryNotNull() throws Exception {
+ assertNotNull(TaskRecord.getTaskRecordFactory());
+ }
+
+ @Test
+ public void testCreateTestRecordUsingCustomizedFactory() throws Exception {
+ TestTaskRecordFactory factory = new TestTaskRecordFactory();
+ TaskRecord.setTaskRecordFactory(factory);
+
+ assertFalse(factory.mCreated);
+
+ TaskRecord.create(null, 0, null, null, null, null);
+
+ assertTrue(factory.mCreated);
+ }
+
+ private static class TestTaskRecordFactory extends TaskRecordFactory {
+ private boolean mCreated = false;
+
+ @Override
+ TaskRecord create(ActivityManagerService service, int taskId, ActivityInfo info,
+ Intent intent,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
+ mCreated = true;
+ return null;
+ }
+
+ @Override
+ TaskRecord create(ActivityManagerService service, int taskId, ActivityInfo info,
+ Intent intent,
+ ActivityManager.TaskDescription taskDescription) {
+ mCreated = true;
+ return null;
+ }
+
+ @Override
+ TaskRecord create(ActivityManagerService service, int taskId, Intent intent,
+ Intent affinityIntent, String affinity, String rootAffinity,
+ ComponentName realActivity,
+ ComponentName origActivity, boolean rootWasReset, boolean autoRemoveRecents,
+ boolean askedCompatMode, int userId, int effectiveUid, String lastDescription,
+ ArrayList<ActivityRecord> activities, long lastTimeMoved,
+ boolean neverRelinquishIdentity,
+ ActivityManager.TaskDescription lastTaskDescription,
+ int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor,
+ int callingUid, String callingPackage, int resizeMode,
+ boolean supportsPictureInPicture,
+ boolean realActivitySuspended, boolean userSetupComplete, int minWidth,
+ int minHeight) {
+ mCreated = true;
+ return null;
+ }
+
+ @Override
+ TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
+ throws IOException, XmlPullParserException {
+ mCreated = true;
+ return null;
+ }
+ }
+}
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..362856c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -0,0 +1,324 @@
+/*
+ * 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 org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.testng.Assert.expectThrows;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.os.HandlerThread;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+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;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class BackupManagerServiceTest {
+ private static final String TAG = "BMSTest";
+ private static final ComponentName TRANSPORT_COMPONENT =
+ new ComponentName(
+ "com.google.android.gms",
+ "com.google.android.gms.backup.BackupTransportService");
+ private static final String TRANSPORT_NAME = TRANSPORT_COMPONENT.flattenToShortString();
+
+ @Mock private TransportManager mTransportManager;
+ private Context mContext;
+ private HandlerThread mBackupThread;
+ private int mPackageUid;
+ private File mBaseStateDir;
+ private File mDataDir;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ Context baseContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ mContext = spy(new ContextWrapper(baseContext));
+
+ mBackupThread = new HandlerThread("backup-test");
+ mBackupThread.setUncaughtExceptionHandler(
+ (t, e) -> Log.e(TAG, "Uncaught exception in test thread " + t.getName(), e));
+ mBackupThread.start();
+
+ File cacheDir = mContext.getCacheDir();
+ mBaseStateDir = new File(cacheDir, "base_state_dir");
+ mDataDir = new File(cacheDir, "data_dir");
+
+ mPackageUid =
+ mContext.getPackageManager().getPackageUid(TRANSPORT_COMPONENT.getPackageName(), 0);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mBackupThread.quit();
+ mBaseStateDir.delete();
+ mDataDir.delete();
+ }
+
+ @Test
+ public void testConstructor_callsTransportManagerSetTransportBoundListener() throws Exception {
+ createBackupManagerService();
+
+ verify(mTransportManager)
+ .setTransportBoundListener(any(TransportManager.TransportBoundListener.class));
+ }
+
+ @Test
+ public void
+ testUpdateTransportAttributes_whenTransportUidEqualsToCallingUid_callsThroughToTransportManager()
+ throws Exception {
+ grantBackupPermission();
+ RefactoredBackupManagerService backupManagerService = createBackupManagerService();
+ Intent configurationIntent = new Intent();
+ Intent dataManagementIntent = new Intent();
+
+ backupManagerService.updateTransportAttributes(
+ mPackageUid,
+ TRANSPORT_COMPONENT,
+ TRANSPORT_NAME,
+ configurationIntent,
+ "currentDestinationString",
+ dataManagementIntent,
+ "dataManagementLabel");
+
+ verify(mTransportManager)
+ .describeTransport(
+ eq(TRANSPORT_COMPONENT),
+ eq(TRANSPORT_NAME),
+ eq(configurationIntent),
+ eq("currentDestinationString"),
+ eq(dataManagementIntent),
+ eq("dataManagementLabel"));
+ }
+
+ @Test
+ public void testUpdateTransportAttributes_whenTransportUidNotEqualToCallingUid_throwsException()
+ throws Exception {
+ grantBackupPermission();
+ RefactoredBackupManagerService backupManagerService = createBackupManagerService();
+
+ expectThrows(
+ SecurityException.class,
+ () ->
+ backupManagerService.updateTransportAttributes(
+ mPackageUid + 1,
+ TRANSPORT_COMPONENT,
+ TRANSPORT_NAME,
+ new Intent(),
+ "currentDestinationString",
+ new Intent(),
+ "dataManagementLabel"));
+ }
+
+ @Test
+ public void testUpdateTransportAttributes_whenTransportComponentNull_throwsException() {
+ grantBackupPermission();
+ RefactoredBackupManagerService backupManagerService = createBackupManagerService();
+
+ expectThrows(
+ RuntimeException.class,
+ () ->
+ backupManagerService.updateTransportAttributes(
+ mPackageUid,
+ null,
+ TRANSPORT_NAME,
+ new Intent(),
+ "currentDestinationString",
+ new Intent(),
+ "dataManagementLabel"));
+ }
+
+ @Test
+ public void testUpdateTransportAttributes_whenNameNull_throwsException() {
+ grantBackupPermission();
+ RefactoredBackupManagerService backupManagerService = createBackupManagerService();
+
+ expectThrows(
+ RuntimeException.class,
+ () ->
+ backupManagerService.updateTransportAttributes(
+ mPackageUid,
+ TRANSPORT_COMPONENT,
+ null,
+ new Intent(),
+ "currentDestinationString",
+ new Intent(),
+ "dataManagementLabel"));
+ }
+
+ @Test
+ public void testUpdateTransportAttributes_whenCurrentDestinationStringNull_throwsException() {
+ grantBackupPermission();
+ RefactoredBackupManagerService backupManagerService = createBackupManagerService();
+
+ expectThrows(
+ RuntimeException.class,
+ () ->
+ backupManagerService.updateTransportAttributes(
+ mPackageUid,
+ TRANSPORT_COMPONENT,
+ TRANSPORT_NAME,
+ new Intent(),
+ null,
+ new Intent(),
+ "dataManagementLabel"));
+ }
+
+ @Test
+ public void
+ testUpdateTransportAttributes_whenDataManagementArgumentsNullityDontMatch_throwsException() {
+ grantBackupPermission();
+ RefactoredBackupManagerService backupManagerService = createBackupManagerService();
+
+ expectThrows(
+ RuntimeException.class,
+ () ->
+ backupManagerService.updateTransportAttributes(
+ mPackageUid,
+ TRANSPORT_COMPONENT,
+ TRANSPORT_NAME,
+ new Intent(),
+ "currentDestinationString",
+ null,
+ "dataManagementLabel"));
+
+ expectThrows(
+ RuntimeException.class,
+ () ->
+ backupManagerService.updateTransportAttributes(
+ mPackageUid,
+ TRANSPORT_COMPONENT,
+ TRANSPORT_NAME,
+ new Intent(),
+ "currentDestinationString",
+ new Intent(),
+ null));
+ }
+
+ @Test
+ public void
+ testUpdateTransportAttributes_whenDataManagementArgumentsNull_callsThroughToTransportManager() {
+ grantBackupPermission();
+ RefactoredBackupManagerService backupManagerService = createBackupManagerService();
+ Intent configurationIntent = new Intent();
+
+ backupManagerService.updateTransportAttributes(
+ mPackageUid,
+ TRANSPORT_COMPONENT,
+ TRANSPORT_NAME,
+ configurationIntent,
+ "currentDestinationString",
+ null,
+ null);
+
+ verify(mTransportManager)
+ .describeTransport(
+ eq(TRANSPORT_COMPONENT),
+ eq(TRANSPORT_NAME),
+ eq(configurationIntent),
+ eq("currentDestinationString"),
+ eq(null),
+ eq(null));
+ }
+
+ @Test
+ public void
+ testUpdateTransportAttributes_whenPermissionGranted_callsThroughToTransportManager() {
+ grantBackupPermission();
+ RefactoredBackupManagerService backupManagerService = createBackupManagerService();
+ Intent configurationIntent = new Intent();
+ Intent dataManagementIntent = new Intent();
+
+ backupManagerService.updateTransportAttributes(
+ mPackageUid,
+ TRANSPORT_COMPONENT,
+ TRANSPORT_NAME,
+ configurationIntent,
+ "currentDestinationString",
+ dataManagementIntent,
+ "dataManagementLabel");
+
+ verify(mTransportManager)
+ .describeTransport(
+ eq(TRANSPORT_COMPONENT),
+ eq(TRANSPORT_NAME),
+ eq(configurationIntent),
+ eq("currentDestinationString"),
+ eq(dataManagementIntent),
+ eq("dataManagementLabel"));
+ }
+
+ @Test
+ public void testUpdateTransportAttributes_whenPermissionDenied_throwsSecurityException() {
+ denyBackupPermission();
+ RefactoredBackupManagerService backupManagerService = createBackupManagerService();
+
+ expectThrows(
+ SecurityException.class,
+ () ->
+ backupManagerService.updateTransportAttributes(
+ mPackageUid,
+ TRANSPORT_COMPONENT,
+ TRANSPORT_NAME,
+ new Intent(),
+ "currentDestinationString",
+ new Intent(),
+ "dataManagementLabel"));
+ }
+
+ private RefactoredBackupManagerService createBackupManagerService() {
+ return new RefactoredBackupManagerService(
+ mContext,
+ new Trampoline(mContext),
+ mBackupThread,
+ mBaseStateDir,
+ mDataDir,
+ mTransportManager);
+ }
+
+ private void grantBackupPermission() {
+ doNothing().when(mContext).enforceCallingOrSelfPermission(any(), anyString());
+ }
+
+ private void denyBackupPermission() {
+ doThrow(new SecurityException())
+ .when(mContext)
+ .enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.BACKUP), anyString());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
index 27ef9d7..5786095 100644
--- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
@@ -82,8 +82,7 @@
};
private final int NON_USER_SYSTEM = UserHandle.USER_SYSTEM + 1;
- @Mock private BackupManagerService mBackupManagerServiceMock;
- @Mock private RefactoredBackupManagerService mRefactoredBackupManagerServiceMock;
+ @Mock private RefactoredBackupManagerService mBackupManagerServiceMock;
@Mock private Context mContextMock;
@Mock private File mSuppressFileMock;
@Mock private File mSuppressFileParentMock;
@@ -102,12 +101,9 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
- TrampolineTestable.sRefactoredBackupManagerServiceMock =
- mRefactoredBackupManagerServiceMock;
- TrampolineTestable.sBackupManagerServiceMock = mBackupManagerServiceMock;
+ TrampolineTestable.sRefactoredBackupManagerServiceMock = mBackupManagerServiceMock;
TrampolineTestable.sSuppressFile = mSuppressFileMock;
TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
- TrampolineTestable.sRefactoredServiceEnabled = false;
TrampolineTestable.sBackupDisabled = false;
when(mSuppressFileMock.getParentFile()).thenReturn(mSuppressFileParentMock);
@@ -163,20 +159,6 @@
}
@Test
- public void createService_refactoredServiceEnabled() {
- TrampolineTestable.sRefactoredServiceEnabled = true;
-
- assertEquals(mRefactoredBackupManagerServiceMock, mTrampoline.createService());
- }
-
- @Test
- public void createService_refactoredServiceDisabled() {
- TrampolineTestable.sRefactoredServiceEnabled = false;
-
- assertEquals(mBackupManagerServiceMock, mTrampoline.createService());
- }
-
- @Test
public void setBackupServiceActive_callerSystemUid_serviceCreated() {
TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
@@ -559,6 +541,24 @@
}
@Test
+ public void describeTransport_calledBeforeInitialize_ignored() throws RemoteException {
+ mTrampoline.updateTransportAttributes(TRANSPORT_COMPONENT_NAME, TRANSPORT_NAME, null,
+ "Transport Destination", null, "Data Management");
+ verifyNoMoreInteractions(mBackupManagerServiceMock);
+ }
+
+ @Test
+ public void describeTransport_forwarded() throws RemoteException {
+ when(mBackupManagerServiceMock.getTransportWhitelist()).thenReturn(TRANSPORTS);
+
+ mTrampoline.initialize(UserHandle.USER_SYSTEM);
+ mTrampoline.updateTransportAttributes(TRANSPORT_COMPONENT_NAME, TRANSPORT_NAME, null,
+ "Transport Destination", null, "Data Management");
+ verify(mBackupManagerServiceMock).updateTransportAttributes(TRANSPORT_COMPONENT_NAME,
+ TRANSPORT_NAME, null, "Transport Destination", null, "Data Management");
+ }
+
+ @Test
public void selectBackupTransport_calledBeforeInitialize_ignored() throws RemoteException {
mTrampoline.selectBackupTransport(TRANSPORT_NAME);
verifyNoMoreInteractions(mBackupManagerServiceMock);
@@ -861,10 +861,8 @@
private static class TrampolineTestable extends Trampoline {
static boolean sBackupDisabled = false;
- static boolean sRefactoredServiceEnabled = false;
static File sSuppressFile = null;
static int sCallingUid = -1;
- static BackupManagerService sBackupManagerServiceMock = null;
static RefactoredBackupManagerService sRefactoredBackupManagerServiceMock = null;
private int mCreateServiceCallsCount = 0;
@@ -873,12 +871,6 @@
}
@Override
- protected BackupManagerServiceInterface createService() {
- mCreateServiceCallsCount++;
- return super.createService();
- }
-
- @Override
public boolean isBackupDisabled() {
return sBackupDisabled;
}
@@ -894,20 +886,11 @@
}
@Override
- protected boolean isRefactoredServiceEnabled() {
- return sRefactoredServiceEnabled;
- }
-
- @Override
protected BackupManagerServiceInterface createRefactoredBackupManagerService() {
+ mCreateServiceCallsCount++;
return sRefactoredBackupManagerServiceMock;
}
- @Override
- protected BackupManagerServiceInterface createBackupManagerService() {
- return sBackupManagerServiceMock;
- }
-
int getCreateServiceCallsCount() {
return mCreateServiceCallsCount;
}
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java
index 87c587a..c40b411 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java
@@ -20,6 +20,7 @@
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_ID;
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME;
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION;
+import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION;
import static com.google.common.truth.Truth.assertThat;
@@ -102,11 +103,40 @@
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(mMonitorMock).onEvent(bundleCaptor.capture());
Bundle eventBundle = bundleCaptor.getValue();
- assertThat(eventBundle.size()).isEqualTo(6);
+ assertThat(eventBundle.size()).isEqualTo(7);
assertThat(eventBundle.getInt(EXTRA_LOG_EVENT_ID)).isEqualTo(1);
assertThat(eventBundle.getInt(EXTRA_LOG_EVENT_CATEGORY)).isEqualTo(2);
assertThat(eventBundle.getString(EXTRA_LOG_EVENT_PACKAGE_NAME)).isEqualTo("test.package");
assertThat(eventBundle.getInt(EXTRA_LOG_EVENT_PACKAGE_VERSION)).isEqualTo(3);
+ assertThat(eventBundle.getLong(EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION)).isEqualTo(3);
+ assertThat(eventBundle.getInt("key1")).isEqualTo(4);
+ assertThat(eventBundle.getString("key2")).isEqualTo("value2");
+ }
+
+ @Test
+ public void monitorEvent_packageAndExtrasAreNotNull_fillsBundleCorrectlyLong() throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test.package";
+ packageInfo.versionCode = 3;
+ packageInfo.versionCodeMajor = 10;
+ Bundle extras = new Bundle();
+ extras.putInt("key1", 4);
+ extras.putString("key2", "value2");
+
+ IBackupManagerMonitor result = BackupManagerMonitorUtils.monitorEvent(mMonitorMock, 1,
+ packageInfo, 2, extras);
+
+ assertThat(result).isEqualTo(mMonitorMock);
+ ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
+ verify(mMonitorMock).onEvent(bundleCaptor.capture());
+ Bundle eventBundle = bundleCaptor.getValue();
+ assertThat(eventBundle.size()).isEqualTo(7);
+ assertThat(eventBundle.getInt(EXTRA_LOG_EVENT_ID)).isEqualTo(1);
+ assertThat(eventBundle.getInt(EXTRA_LOG_EVENT_CATEGORY)).isEqualTo(2);
+ assertThat(eventBundle.getString(EXTRA_LOG_EVENT_PACKAGE_NAME)).isEqualTo("test.package");
+ assertThat(eventBundle.getInt(EXTRA_LOG_EVENT_PACKAGE_VERSION)).isEqualTo(3);
+ assertThat(eventBundle.getLong(EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION)).isEqualTo(
+ (10L << 32) | 3);
assertThat(eventBundle.getInt("key1")).isEqualTo(4);
assertThat(eventBundle.getString("key2")).isEqualTo("value2");
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index ae4b569..d168479 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -373,6 +373,11 @@
}
@Override
+ void settingsSystemPutString(String name, String value) {
+ services.settings.settingsSystemPutString(name, value);
+ }
+
+ @Override
int settingsGlobalGetInt(String name, int def) {
return services.settings.settingsGlobalGetInt(name, def);
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 6de3395..ca918c6 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3090,6 +3090,27 @@
assertEquals(-1, dpm.getLastSecurityLogRetrievalTime());
}
+ public void testSetSystemSettingFailWithNonWhitelistedSettings() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ setupDeviceOwner();
+ assertExpectException(SecurityException.class, null, () ->
+ dpm.setSystemSetting(admin1, Settings.System.SCREEN_BRIGHTNESS_FOR_VR, "0"));
+ }
+
+ public void testSetSystemSettingFailWithPO() throws Exception {
+ setupProfileOwner();
+ assertExpectException(SecurityException.class, null, () ->
+ dpm.setSystemSetting(admin1, Settings.System.SCREEN_BRIGHTNESS, "0"));
+ }
+
+ public void testSetSystemSetting() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ setupDeviceOwner();
+ dpm.setSystemSetting(admin1, Settings.System.SCREEN_BRIGHTNESS, "0");
+ verify(getServices().settings).settingsSystemPutString(
+ Settings.System.SCREEN_BRIGHTNESS, "0");
+ }
+
public void testSetTime() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 7e11e87..e2ba4d5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -103,7 +103,7 @@
long callingIdentity = clearCallingIdentity();
Throwable throwableToPropagate = null;
try {
- action.run();
+ action.runOrThrow();
} catch (Throwable throwable) {
throwableToPropagate = throwable;
} finally {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 99f54ba..4ee5ba6 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -379,6 +379,9 @@
public void settingsGlobalPutString(String name, String value) {
}
+ public void settingsSystemPutString(String name, String value) {
+ }
+
public int settingsGlobalGetInt(String name, int value) {
return 0;
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java
index db317a0..a92d1db 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java
@@ -20,8 +20,6 @@
import android.os.Parcel;
import android.test.suitebuilder.annotation.SmallTest;
-import static junit.framework.Assert.assertEquals;
-
@SmallTest
public class NetworkEventTest extends DpmTestBase {
@@ -30,6 +28,7 @@
*/
public void testConnectEventParceling() {
ConnectEvent event = new ConnectEvent("127.0.0.1", 80, "com.android.whateverdude", 100000);
+ event.setId(5L);
Parcel p = Parcel.obtain();
p.writeParcelable(event, 0);
p.setDataPosition(0);
@@ -39,6 +38,7 @@
assertEquals(event.getPort(), unparceledEvent.getPort());
assertEquals(event.getPackageName(), unparceledEvent.getPackageName());
assertEquals(event.getTimestamp(), unparceledEvent.getTimestamp());
+ assertEquals(event.getId(), unparceledEvent.getId());
}
/**
@@ -47,6 +47,7 @@
public void testDnsEventParceling() {
DnsEvent event = new DnsEvent("d.android.com", new String[]{"192.168.0.1", "127.0.0.1"}, 2,
"com.android.whateverdude", 100000);
+ event.setId(5L);
Parcel p = Parcel.obtain();
p.writeParcelable(event, 0);
p.setDataPosition(0);
@@ -59,5 +60,6 @@
unparceledEvent.getTotalResolvedAddressCount());
assertEquals(event.getPackageName(), unparceledEvent.getPackageName());
assertEquals(event.getTimestamp(), unparceledEvent.getTimestamp());
+ assertEquals(event.getId(), unparceledEvent.getId());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
index 6938e0f..926009e 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
@@ -94,12 +94,29 @@
}
@Test
- public void testStartStopTracker() {
+ public void testStartStopTrackerScreenOnOff() {
+ mInjector.mInteractive = false;
startTracker(mTracker);
- assertNotNull(mInjector.mSensorListener);
+ assertNull(mInjector.mSensorListener);
assertNotNull(mInjector.mSettingsObserver);
assertNotNull(mInjector.mBroadcastReceiver);
assertTrue(mInjector.mIdleScheduled);
+ Intent onIntent = new Intent();
+ onIntent.setAction(Intent.ACTION_SCREEN_ON);
+ mInjector.mBroadcastReceiver.onReceive(InstrumentationRegistry.getContext(),
+ onIntent);
+ assertNotNull(mInjector.mSensorListener);
+
+ Intent offIntent = new Intent();
+ offIntent.setAction(Intent.ACTION_SCREEN_OFF);
+ mInjector.mBroadcastReceiver.onReceive(InstrumentationRegistry.getContext(),
+ offIntent);
+ assertNull(mInjector.mSensorListener);
+
+ mInjector.mBroadcastReceiver.onReceive(InstrumentationRegistry.getContext(),
+ onIntent);
+ assertNotNull(mInjector.mSensorListener);
+
mTracker.stop();
assertNull(mInjector.mSensorListener);
assertNull(mInjector.mSettingsObserver);
@@ -117,7 +134,7 @@
mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2));
mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
Settings.System.SCREEN_BRIGHTNESS));
- List<BrightnessChangeEvent> events = mTracker.getEvents(0).getList();
+ List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
mTracker.stop();
assertEquals(1, events.size());
@@ -152,7 +169,9 @@
final long sensorTime = mInjector.currentTimeMillis();
mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
Settings.System.SCREEN_BRIGHTNESS));
- List<BrightnessChangeEvent> events = mTracker.getEvents(0).getList();
+ List<BrightnessChangeEvent> eventsNoPackage
+ = mTracker.getEvents(0, false).getList();
+ List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
mTracker.stop();
assertEquals(1, events.size());
@@ -167,6 +186,9 @@
assertEquals(3333, event.colorTemperature);
assertEquals("a.package", event.packageName);
assertEquals(0, event.userId);
+
+ assertEquals(1, eventsNoPackage.size());
+ assertNull(eventsNoPackage.get(0).packageName);
}
@Test
@@ -183,7 +205,7 @@
(int) mInjector.mSystemIntSettings.get(Settings.System.SCREEN_BRIGHTNESS));
mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
Settings.System.SCREEN_BRIGHTNESS));
- List<BrightnessChangeEvent> events = mTracker.getEvents(0).getList();
+ List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
// No events because we filtered out our change.
assertEquals(0, events.size());
@@ -200,7 +222,7 @@
secondUserUpdateBrightness);
mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
Settings.System.SCREEN_BRIGHTNESS));
- events = mTracker.getEvents(0).getList();
+ events = mTracker.getEvents(0, true).getList();
assertEquals(2, events.size());
// First event is change from system update (20) to first user update (20)
@@ -225,7 +247,7 @@
mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
Settings.System.SCREEN_BRIGHTNESS));
}
- List<BrightnessChangeEvent> events = mTracker.getEvents(0).getList();
+ List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
mTracker.stop();
// Should be capped at 100 events, and they should be the most recent 100.
@@ -249,7 +271,7 @@
}
mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
Settings.System.SCREEN_BRIGHTNESS));
- List<BrightnessChangeEvent> events = mTracker.getEvents(0).getList();
+ List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
mTracker.stop();
assertEquals(1, events.size());
@@ -300,7 +322,7 @@
+ Long.toString(twoMonthsAgo) + "," + Long.toString(twoMonthsAgo) + "\"/>"
+ "</events>";
tracker.readEventsLocked(getInputStream(eventFile));
- List<BrightnessChangeEvent> events = tracker.getEvents(0).getList();
+ List<BrightnessChangeEvent> events = tracker.getEvents(0, true).getList();
assertEquals(1, events.size());
BrightnessChangeEvent event = events.get(0);
assertEquals(someTimeAgo, event.timeStamp);
@@ -313,7 +335,7 @@
assertEquals(1.0f, event.batteryLevel, 0.01);
assertEquals("com.example.app", event.packageName);
- events = tracker.getEvents(1).getList();
+ events = tracker.getEvents(1, true).getList();
assertEquals(1, events.size());
event = events.get(0);
assertEquals(someTimeAgo, event.timeStamp);
@@ -342,7 +364,7 @@
} catch (IOException e) {
// Expected;
}
- assertEquals(0, tracker.getEvents(0).getList().size());
+ assertEquals(0, tracker.getEvents(0, true).getList().size());
// Missing lux value.
eventFile =
@@ -357,7 +379,7 @@
} catch (IOException e) {
// Expected;
}
- assertEquals(0, tracker.getEvents(0).getList().size());
+ assertEquals(0, tracker.getEvents(0, true).getList().size());
}
@Test
@@ -388,7 +410,7 @@
BrightnessTracker tracker = new BrightnessTracker(InstrumentationRegistry.getContext(),
mInjector);
tracker.readEventsLocked(input);
- List<BrightnessChangeEvent> events = tracker.getEvents(0).getList();
+ List<BrightnessChangeEvent> events = tracker.getEvents(0, true).getList();
assertEquals(1, events.size());
BrightnessChangeEvent event = events.get(0);
@@ -425,12 +447,12 @@
Settings.System.SCREEN_BRIGHTNESS));
final long eventTime = mInjector.currentTimeMillis();
- List<BrightnessChangeEvent> events = mTracker.getEvents(0).getList();
+ List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
assertEquals(2, events.size());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
mTracker.writeEventsLocked(baos);
- events = mTracker.getEvents(0).getList();
+ events = mTracker.getEvents(0, true).getList();
mTracker.stop();
assertEquals(1, events.size());
@@ -532,7 +554,6 @@
mInjector.waitForHandler();
}
-
private static final class Idle implements MessageQueue.IdleHandler {
private boolean mIdle;
@@ -565,6 +586,7 @@
long mElapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos();
Handler mHandler;
boolean mIdleScheduled;
+ boolean mInteractive = true;
public TestInjector(Handler handler) {
mHandler = handler;
@@ -577,7 +599,7 @@
@Override
public void registerSensorListener(Context context,
- SensorEventListener sensorListener) {
+ SensorEventListener sensorListener, Handler handler) {
mSensorListener = sensorListener;
}
@@ -694,5 +716,9 @@
public void cancelIdleJob(Context context) {
mIdleScheduled = false;
}
+
+ public boolean isInteractive(Context context) {
+ return mInteractive;
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 025ebc3..8cf575e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -1075,6 +1075,7 @@
final PackageInfo ret = new PackageInfo();
ret.packageName = pi.packageName;
ret.versionCode = pi.versionCode;
+ ret.versionCodeMajor = pi.versionCodeMajor;
ret.lastUpdateTime = pi.lastUpdateTime;
ret.applicationInfo = new ApplicationInfo(pi.applicationInfo);
@@ -2120,22 +2121,30 @@
PACKAGE_FALLBACK_LAUNCHER_PRIORITY);
}
- protected void makeCallerForeground() {
+ protected void makeUidForeground(int uid) {
try {
mService.mUidObserver.onUidStateChanged(
- mInjectedCallingUid, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
+ uid, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+
+ protected void makeCallerForeground() {
+ makeUidForeground(mInjectedCallingUid);
+ }
+
+ protected void makeUidBackground(int uid) {
+ try {
+ mService.mUidObserver.onUidStateChanged(
+ uid, ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
}
protected void makeCallerBackground() {
- try {
- mService.mUidObserver.onUidStateChanged(
- mInjectedCallingUid, ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0);
- } catch (RemoteException e) {
- e.rethrowAsRuntimeException();
- }
+ makeUidBackground(mInjectedCallingUid);
}
protected void publishManifestShortcutsAsCaller(int resId) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java
deleted file mode 100644
index e6b4540f..0000000
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2016 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.pm;
-
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PermissionInfo;
-import android.platform.test.annotations.GlobalPresubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.util.ArraySet;
-
-import com.android.internal.os.RoSystemProperties;
-import com.android.internal.util.ArrayUtils;
-import com.android.server.SystemConfig;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-import static android.content.pm.PackageManager.GET_PERMISSIONS;
-import static junit.framework.Assert.assertTrue;
-
-
-/**
- * Presubmit tests for {@link PackageManager}.
- */
-@RunWith(AndroidJUnit4.class)
-public class PackageManagerPresubmitTest {
-
- private Context mContext;
-
- private PackageManager mPackageManager;
-
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getContext();
- mPackageManager = mContext.getPackageManager();
- }
-
- /**
- * <p>This test ensures that all signature|privileged permissions are granted to priv-apps.
- * If CONTROL_PRIVAPP_PERMISSIONS_ENFORCE is set, the test also verifies that
- * granted permissions are whitelisted in {@link SystemConfig}
- */
- @Test
- @SmallTest
- @GlobalPresubmit
- public void testPrivAppPermissions() throws PackageManager.NameNotFoundException {
- List<PackageInfo> installedPackages = mPackageManager
- .getInstalledPackages(PackageManager.MATCH_UNINSTALLED_PACKAGES | GET_PERMISSIONS);
- for (PackageInfo packageInfo : installedPackages) {
- if (!packageInfo.applicationInfo.isPrivilegedApp()
- || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(packageInfo.packageName)) {
- continue;
- }
- testPackagePrivAppPermission(packageInfo);
- }
-
- }
-
- private void testPackagePrivAppPermission(PackageInfo packageInfo)
- throws PackageManager.NameNotFoundException {
- String packageName = packageInfo.packageName;
- ArraySet<String> privAppPermissions = SystemConfig.getInstance()
- .getPrivAppPermissions(packageName);
- if (ArrayUtils.isEmpty(packageInfo.requestedPermissions)) {
- return;
- }
- for (int i = 0; i < packageInfo.requestedPermissions.length; i++) {
- String pName = packageInfo.requestedPermissions[i];
- int protectionLevel;
- boolean platformPermission;
- try {
- PermissionInfo permissionInfo = mPackageManager.getPermissionInfo(pName, 0);
- platformPermission = PackageManagerService.PLATFORM_PACKAGE_NAME.equals(
- permissionInfo.packageName);
- protectionLevel = permissionInfo.protectionLevel;
- } catch (PackageManager.NameNotFoundException e) {
- continue;
- }
- if ((protectionLevel & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0) {
- boolean granted = (packageInfo.requestedPermissionsFlags[i]
- & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
- // if privapp permissions are enforced, platform permissions must be whitelisted
- // in SystemConfig
- if (platformPermission && RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
- assertTrue("Permission " + pName + " should be declared in "
- + "privapp-permissions-<category>.xml file for package "
- + packageName,
- privAppPermissions != null && privAppPermissions.contains(pName));
- }
- assertTrue("Permission " + pName + " should be granted to " + packageName, granted);
- }
- }
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index fd105bc..0995f2e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -577,7 +577,7 @@
new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
pkg.usesStaticLibraries = new ArrayList<>(
Arrays.asList("foo.bar1", "foo.bar2", "foo.bar3"));
- pkg.usesStaticLibrariesVersions = new int[] {2, 4, 6};
+ pkg.usesStaticLibrariesVersions = new long[] {2, 4, 6};
settings.insertPackageSettingLPw(ps, pkg);
assertEquals(pkg, ps.pkg);
assertArrayEquals(pkg.usesStaticLibraries.toArray(new String[0]), ps.usesStaticLibraries);
@@ -602,6 +602,11 @@
Arrays.equals(a, b));
}
+ private void assertArrayEquals(long[] a, long[] b) {
+ assertTrue("Expected: " + Arrays.toString(a) + ", actual: " + Arrays.toString(b),
+ Arrays.equals(a, b));
+ }
+
private void verifyUserState(PackageUserState userState, PackageUserState oldUserState,
boolean userStateChanged) {
verifyUserState(userState, oldUserState, userStateChanged, false /*notLaunched*/,
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 1f9a243..36cc3a0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -471,7 +471,7 @@
pkg.usesStaticLibraries.add("foo23");
pkg.usesStaticLibrariesCertDigests = new String[1][];
pkg.usesStaticLibrariesCertDigests[0] = new String[] { "digest" };
- pkg.usesStaticLibrariesVersions = new int[] { 100 };
+ pkg.usesStaticLibrariesVersions = new long[] { 100 };
pkg.libraryNames = new ArrayList<>();
pkg.libraryNames.add("foo10");
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index f92b575..ee33e79 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -7912,4 +7912,35 @@
.forAllShortcuts(si -> assertTrue(si.isReturnedByServer()));
});
}
+
+ public void testIsForegroundDefaultLauncher_true() {
+ final ComponentName defaultLauncher = new ComponentName("default", "launcher");
+ final int uid = 1024;
+
+ setDefaultLauncher(UserHandle.USER_SYSTEM, defaultLauncher);
+ makeUidForeground(uid);
+
+ assertTrue(mInternal.isForegroundDefaultLauncher("default", uid));
+ }
+
+
+ public void testIsForegroundDefaultLauncher_defaultButNotForeground() {
+ final ComponentName defaultLauncher = new ComponentName("default", "launcher");
+ final int uid = 1024;
+
+ setDefaultLauncher(UserHandle.USER_SYSTEM, defaultLauncher);
+ makeUidBackground(uid);
+
+ assertFalse(mInternal.isForegroundDefaultLauncher("default", uid));
+ }
+
+ public void testIsForegroundDefaultLauncher_foregroundButNotDefault() {
+ final ComponentName defaultLauncher = new ComponentName("default", "launcher");
+ final int uid = 1024;
+
+ setDefaultLauncher(UserHandle.USER_SYSTEM, defaultLauncher);
+ makeUidForeground(uid);
+
+ assertFalse(mInternal.isForegroundDefaultLauncher("another", uid));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
new file mode 100644
index 0000000..d1e0132
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
@@ -0,0 +1,256 @@
+/*
+ * 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.policy;
+
+import android.annotation.Nullable;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.view.Display;
+import android.view.DisplayCutout;
+import android.view.IApplicationToken;
+import android.view.WindowManager;
+
+public class FakeWindowState implements WindowManagerPolicy.WindowState {
+
+ public final Rect parentFrame = new Rect();
+ public final Rect displayFrame = new Rect();
+ public final Rect overscanFrame = new Rect();
+ public final Rect contentFrame = new Rect();
+ public final Rect visibleFrame = new Rect();
+ public final Rect decorFrame = new Rect();
+ public final Rect stableFrame = new Rect();
+ public Rect outsetFrame = new Rect();
+
+ public DisplayCutout displayCutout;
+
+ public WindowManager.LayoutParams attrs;
+ public int displayId;
+ public boolean isVoiceInteraction;
+ public boolean inMultiWindowMode;
+ public boolean visible = true;
+ public int surfaceLayer = 1;
+
+ public boolean policyVisible = true;
+
+ @Override
+ public int getOwningUid() {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public String getOwningPackage() {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overlayFrame,
+ Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame,
+ @Nullable Rect outsetFrame, DisplayCutout displayCutout) {
+ this.parentFrame.set(parentFrame);
+ this.displayFrame.set(displayFrame);
+ this.overscanFrame.set(overlayFrame);
+ this.contentFrame.set(contentFrame);
+ this.visibleFrame.set(visibleFrame);
+ this.decorFrame.set(decorFrame);
+ this.stableFrame.set(stableFrame);
+ this.outsetFrame = outsetFrame == null ? null : new Rect(outsetFrame);
+ this.displayCutout = displayCutout;
+ }
+
+ @Override
+ public Rect getFrameLw() {
+ return parentFrame;
+ }
+
+ @Override
+ public Point getShownPositionLw() {
+ return new Point(parentFrame.left, parentFrame.top);
+ }
+
+ @Override
+ public Rect getDisplayFrameLw() {
+ return displayFrame;
+ }
+
+ @Override
+ public Rect getOverscanFrameLw() {
+ return overscanFrame;
+ }
+
+ @Override
+ public Rect getContentFrameLw() {
+ return contentFrame;
+ }
+
+ @Override
+ public Rect getVisibleFrameLw() {
+ return visibleFrame;
+ }
+
+ @Override
+ public boolean getGivenInsetsPendingLw() {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public Rect getGivenContentInsetsLw() {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public Rect getGivenVisibleInsetsLw() {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public WindowManager.LayoutParams getAttrs() {
+ return attrs;
+ }
+
+ @Override
+ public boolean getNeedsMenuLw(WindowManagerPolicy.WindowState bottom) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public int getSystemUiVisibility() {
+ return attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility;
+ }
+
+ @Override
+ public int getSurfaceLayer() {
+ return surfaceLayer;
+ }
+
+ @Override
+ public int getBaseType() {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public IApplicationToken getAppToken() {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public boolean isVoiceInteraction() {
+ return isVoiceInteraction;
+ }
+
+ @Override
+ public boolean hasAppShownWindows() {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public boolean isVisibleLw() {
+ return visible && policyVisible;
+ }
+
+ @Override
+ public boolean isDisplayedLw() {
+ return isVisibleLw();
+ }
+
+ @Override
+ public boolean isAnimatingLw() {
+ return false;
+ }
+
+ @Override
+ public boolean canAffectSystemUiFlags() {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public boolean isGoneForLayoutLw() {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public boolean isDrawnLw() {
+ return true;
+ }
+
+ @Override
+ public boolean hasDrawnLw() {
+ return true;
+ }
+
+ @Override
+ public boolean hideLw(boolean doAnimation) {
+ if (!policyVisible) {
+ return false;
+ }
+ policyVisible = false;
+ return true;
+ }
+
+ @Override
+ public boolean showLw(boolean doAnimation) {
+ if (policyVisible) {
+ return false;
+ }
+ policyVisible = true;
+ return true;
+ }
+
+ @Override
+ public boolean isAlive() {
+ return true;
+ }
+
+ @Override
+ public boolean isDefaultDisplay() {
+ return displayId == Display.DEFAULT_DISPLAY;
+ }
+
+ @Override
+ public boolean isDimming() {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public int getWindowingMode() {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public boolean isInMultiWindowMode() {
+ return inMultiWindowMode;
+ }
+
+ @Override
+ public int getRotationAnimationHint() {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public boolean isInputMethodWindow() {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public int getDisplayId() {
+ return displayId;
+ }
+
+ @Override
+ public boolean canAcquireSleepToken() {
+ throw new UnsupportedOperationException("not implemented");
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
new file mode 100644
index 0000000..9a6da0e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
@@ -0,0 +1,233 @@
+/*
+ * 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.policy;
+
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA;
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+
+import static org.junit.Assert.assertEquals;
+
+import android.graphics.PixelFormat;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.Surface;
+import android.view.WindowManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class PhoneWindowManagerLayoutTest extends PhoneWindowManagerTestBase {
+
+ private FakeWindowState mAppWindow;
+
+ @Before
+ public void setUp() throws Exception {
+ mAppWindow = new FakeWindowState();
+ mAppWindow.attrs = new WindowManager.LayoutParams(MATCH_PARENT, MATCH_PARENT,
+ TYPE_APPLICATION,
+ FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+ PixelFormat.TRANSLUCENT);
+
+ addStatusBar();
+ addNavigationBar();
+ }
+
+ @Test
+ public void layoutWindowLw_appDrawsBars() throws Exception {
+ mAppWindow.attrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mPolicy.addWindow(mAppWindow);
+
+ mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
+
+ assertInsetByTopBottom(mAppWindow.parentFrame, 0, 0);
+ assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
+ }
+
+ @Test
+ public void layoutWindowLw_appWontDrawBars() throws Exception {
+ mAppWindow.attrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mPolicy.addWindow(mAppWindow);
+
+ mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
+
+ assertInsetByTopBottom(mAppWindow.parentFrame, 0, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mAppWindow.decorFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ }
+
+ @Test
+ public void layoutWindowLw_appWontDrawBars_forceStatus() throws Exception {
+ mAppWindow.attrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mAppWindow.attrs.privateFlags |= PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
+ mPolicy.addWindow(mAppWindow);
+
+ mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
+
+ assertInsetByTopBottom(mAppWindow.parentFrame, 0, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mAppWindow.decorFrame, 0, NAV_BAR_HEIGHT);
+ }
+
+ @Test
+ public void addingWindow_doesNotTamperWithSysuiFlags() {
+ mAppWindow.attrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mPolicy.addWindow(mAppWindow);
+
+ assertEquals(0, mAppWindow.attrs.systemUiVisibility);
+ assertEquals(0, mAppWindow.attrs.subtreeSystemUiVisibility);
+ }
+
+ @Test
+ public void layoutWindowLw_withDisplayCutout() {
+ addDisplayCutout();
+
+ mPolicy.addWindow(mAppWindow);
+
+ mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
+
+ assertInsetByTopBottom(mAppWindow.parentFrame, 0, 0);
+ assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
+ }
+
+ @Test
+ public void layoutWindowLw_withDisplayCutout_fullscreen() {
+ addDisplayCutout();
+
+ mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+ mPolicy.addWindow(mAppWindow);
+
+ mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
+
+ assertInsetByTopBottom(mAppWindow.parentFrame, STATUS_BAR_HEIGHT, 0);
+ assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
+ }
+
+ @Test
+ public void layoutWindowLw_withDisplayCutout_fullscreenInCutout() {
+ addDisplayCutout();
+
+ mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+ mAppWindow.attrs.flags2 |= FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA;
+ mPolicy.addWindow(mAppWindow);
+
+ mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
+
+ assertInsetByTopBottom(mAppWindow.parentFrame, 0, 0);
+ assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
+ }
+
+
+ @Test
+ public void layoutWindowLw_withDisplayCutout_landscape() {
+ addDisplayCutout();
+ setRotation(ROTATION_90);
+ mPolicy.addWindow(mAppWindow);
+
+ mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
+
+ assertInsetBy(mAppWindow.parentFrame, DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+ assertInsetBy(mAppWindow.stableFrame, 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+ assertInsetBy(mAppWindow.contentFrame,
+ DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+ assertInsetBy(mAppWindow.decorFrame, 0, 0, 0, 0);
+ }
+
+ @Test
+ public void layoutWindowLw_withDisplayCutout_seascape() {
+ addDisplayCutout();
+ setRotation(ROTATION_270);
+ mPolicy.addWindow(mAppWindow);
+
+ mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
+
+ assertInsetBy(mAppWindow.parentFrame, 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
+ assertInsetBy(mAppWindow.stableFrame, NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0);
+ assertInsetBy(mAppWindow.contentFrame,
+ NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, 0);
+ assertInsetBy(mAppWindow.decorFrame, 0, 0, 0, 0);
+ }
+
+ @Test
+ public void layoutWindowLw_withDisplayCutout_fullscreen_landscape() {
+ addDisplayCutout();
+ setRotation(ROTATION_90);
+
+ mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+ mPolicy.addWindow(mAppWindow);
+
+ mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
+
+ assertInsetBy(mAppWindow.parentFrame, DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+ assertInsetBy(mAppWindow.stableFrame, 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+ assertInsetBy(mAppWindow.contentFrame,
+ DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+ assertInsetBy(mAppWindow.decorFrame, 0, 0, 0, 0);
+ }
+
+ @Test
+ public void layoutWindowLw_withDisplayCutout_fullscreenInCutout_landscape() {
+ addDisplayCutout();
+ setRotation(ROTATION_90);
+
+ mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+ mAppWindow.attrs.flags2 |= FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA;
+ mPolicy.addWindow(mAppWindow);
+
+ mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
+
+ assertInsetBy(mAppWindow.parentFrame, 0, 0, 0, 0);
+ assertInsetBy(mAppWindow.stableFrame, 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+ assertInsetBy(mAppWindow.contentFrame,
+ DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+ assertInsetBy(mAppWindow.decorFrame, 0, 0, 0, 0);
+ }
+
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
new file mode 100644
index 0000000..e7e9abad
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
@@ -0,0 +1,210 @@
+/*
+ * 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.policy;
+
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.os.UserHandle;
+import android.support.test.InstrumentationRegistry;
+import android.testing.TestableResources;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.Gravity;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IAccessibilityManager;
+
+import com.android.server.policy.keyguard.KeyguardServiceDelegate;
+import com.android.server.wm.DisplayFrames;
+
+import org.junit.Before;
+
+public class PhoneWindowManagerTestBase {
+ static final int DISPLAY_WIDTH = 500;
+ static final int DISPLAY_HEIGHT = 1000;
+
+ static final int STATUS_BAR_HEIGHT = 10;
+ static final int NAV_BAR_HEIGHT = 15;
+ static final int DISPLAY_CUTOUT_HEIGHT = 8;
+
+ TestablePhoneWindowManager mPolicy;
+ TestContextWrapper mContext;
+ DisplayFrames mFrames;
+
+ FakeWindowState mStatusBar;
+ FakeWindowState mNavigationBar;
+
+ @Before
+ public void setUpBase() throws Exception {
+ mContext = new TestContextWrapper(InstrumentationRegistry.getTargetContext());
+ mContext.getResourceMocker().addOverride(
+ com.android.internal.R.dimen.status_bar_height, STATUS_BAR_HEIGHT);
+ mContext.getResourceMocker().addOverride(
+ com.android.internal.R.dimen.navigation_bar_height, NAV_BAR_HEIGHT);
+ mContext.getResourceMocker().addOverride(
+ com.android.internal.R.dimen.navigation_bar_height_landscape, NAV_BAR_HEIGHT);
+ mContext.getResourceMocker().addOverride(
+ com.android.internal.R.dimen.navigation_bar_width, NAV_BAR_HEIGHT);
+
+ mPolicy = TestablePhoneWindowManager.create(mContext);
+
+ setRotation(ROTATION_0);
+ }
+
+ public void setRotation(int rotation) {
+ DisplayInfo info = new DisplayInfo();
+
+ final boolean flippedDimensions = rotation == ROTATION_90 || rotation == ROTATION_270;
+ info.logicalWidth = flippedDimensions ? DISPLAY_HEIGHT : DISPLAY_WIDTH;
+ info.logicalHeight = flippedDimensions ? DISPLAY_WIDTH : DISPLAY_HEIGHT;
+ info.rotation = rotation;
+
+ mFrames = new DisplayFrames(Display.DEFAULT_DISPLAY, info);
+ }
+
+ public void addStatusBar() {
+ mStatusBar = new FakeWindowState();
+ mStatusBar.attrs = new WindowManager.LayoutParams(MATCH_PARENT, STATUS_BAR_HEIGHT,
+ TYPE_STATUS_BAR, 0 /* flags */, PixelFormat.TRANSLUCENT);
+ mStatusBar.attrs.gravity = Gravity.TOP;
+
+ mPolicy.addWindow(mStatusBar);
+ mPolicy.mLastSystemUiFlags |= View.STATUS_BAR_TRANSPARENT;
+ }
+
+ public void addNavigationBar() {
+ mNavigationBar = new FakeWindowState();
+ mNavigationBar.attrs = new WindowManager.LayoutParams(MATCH_PARENT, NAV_BAR_HEIGHT,
+ TYPE_NAVIGATION_BAR, 0 /* flags */, PixelFormat.TRANSLUCENT);
+ mNavigationBar.attrs.gravity = Gravity.BOTTOM;
+
+ mPolicy.addWindow(mNavigationBar);
+ mPolicy.mHasNavigationBar = true;
+ mPolicy.mLastSystemUiFlags |= View.NAVIGATION_BAR_TRANSPARENT;
+ }
+
+ public void addDisplayCutout() {
+ mPolicy.mEmulateDisplayCutout = true;
+ }
+
+ /** Asserts that {@code actual} is inset by the given amounts from the full display rect. */
+ public void assertInsetBy(Rect actual, int expectedInsetLeft, int expectedInsetTop,
+ int expectedInsetRight, int expectedInsetBottom) {
+ assertEquals(new Rect(expectedInsetLeft, expectedInsetTop,
+ mFrames.mDisplayWidth - expectedInsetRight,
+ mFrames.mDisplayHeight - expectedInsetBottom), actual);
+ }
+
+ /**
+ * Asserts that {@code actual} is inset by the given amounts from the full display rect.
+ *
+ * Convenience wrapper for when only the top and bottom inset are non-zero.
+ */
+ public void assertInsetByTopBottom(Rect actual, int expectedInsetTop, int expectedInsetBottom) {
+ assertInsetBy(actual, 0, expectedInsetTop, 0, expectedInsetBottom);
+ }
+
+ static class TestContextWrapper extends ContextWrapper {
+ private final TestableResources mResourceMocker;
+
+ public TestContextWrapper(Context targetContext) {
+ super(targetContext);
+ mResourceMocker = new TestableResources(targetContext.getResources());
+ }
+
+ @Override
+ public int checkPermission(String permission, int pid, int uid) {
+ return PackageManager.PERMISSION_GRANTED;
+ }
+
+ @Override
+ public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
+ return PackageManager.PERMISSION_GRANTED;
+ }
+
+ @Override
+ public Resources getResources() {
+ return mResourceMocker.getResources();
+ }
+
+ public TestableResources getResourceMocker() {
+ return mResourceMocker;
+ }
+ }
+
+ static class TestablePhoneWindowManager extends PhoneWindowManager {
+
+ public TestablePhoneWindowManager() {
+ }
+
+ @Override
+ void initializeHdmiState() {
+ // Do nothing.
+ }
+
+ @Override
+ Context getSystemUiContext() {
+ return mContext;
+ }
+
+ void addWindow(WindowState state) {
+ if (state instanceof FakeWindowState) {
+ ((FakeWindowState) state).surfaceLayer =
+ getWindowLayerFromTypeLw(state.getAttrs().type);
+ }
+ adjustWindowParamsLw(state, state.getAttrs(), true /* hasStatusBarPermission */);
+ assertEquals(WindowManagerGlobal.ADD_OKAY, prepareAddWindowLw(state, state.getAttrs()));
+ }
+
+ public static TestablePhoneWindowManager create(Context context) {
+ TestablePhoneWindowManager[] policy = new TestablePhoneWindowManager[1];
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ policy[0] = new TestablePhoneWindowManager();
+ policy[0].mContext = context;
+ policy[0].mKeyguardDelegate = mock(KeyguardServiceDelegate.class);
+ policy[0].mAccessibilityManager = new AccessibilityManager(context,
+ mock(IAccessibilityManager.class), UserHandle.USER_CURRENT);
+ policy[0].mSystemGestures = mock(SystemGesturesPointerEventListener.class);
+ policy[0].mNavigationBarCanMove = true;
+ policy[0].mPortraitRotation = ROTATION_0;
+ policy[0].mLandscapeRotation = ROTATION_90;
+ policy[0].mUpsideDownRotation = ROTATION_180;
+ policy[0].mSeascapeRotation = ROTATION_270;
+ policy[0].onConfigurationChanged();
+ });
+ return policy[0];
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/FileUpdaterTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/FileUpdaterTest.java
index 7e2a7d2..7324fe6 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/FileUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/FileUpdaterTest.java
@@ -15,8 +15,9 @@
*/
package com.android.server.power.batterysaver;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
@@ -26,6 +27,7 @@
import static org.mockito.Mockito.verify;
import android.content.Context;
+import android.hardware.camera2.impl.GetCommand;
import android.os.Handler;
import android.os.Looper;
import android.support.test.InstrumentationRegistry;
@@ -40,6 +42,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.io.File;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -72,6 +75,17 @@
void injectWtf(String message, Throwable e) {
mInjector.injectWtf(message, e);
}
+
+ @Override
+ File injectDefaultValuesFilename() {
+ return new File(InstrumentationRegistry.getContext().getCacheDir() +
+ "/test-default.xml");
+ }
+
+ @Override
+ boolean injectShouldSkipWrite() {
+ return false;
+ }
}
private interface Injector {
@@ -334,4 +348,57 @@
reset(mInjector);
testMultiWrites();
}
+
+ @Test
+ public void testWriteReadDefault() throws Exception {
+ doReturn("111").when(mInjector).injectReadFromFileTrimmed("file1");
+ doReturn("222").when(mInjector).injectReadFromFileTrimmed("file2");
+ doReturn("333").when(mInjector).injectReadFromFileTrimmed("file3");
+
+ // Write
+ final ArrayMap<String, String> values = new ArrayMap<>();
+ values.put("file1", "11");
+ values.put("file2", "22");
+ values.put("file3", "33");
+
+ mInstance.writeFiles(values);
+ waitUntilMainHandlerDrain();
+
+ verify(mInjector, times(1)).injectWriteToFile("file1", "11");
+ verify(mInjector, times(1)).injectWriteToFile("file2", "22");
+ verify(mInjector, times(1)).injectWriteToFile("file3", "33");
+
+ // Clear and reload the default.
+ assertEquals(3, mInstance.getDefaultValuesForTest().size());
+ mInstance.getDefaultValuesForTest().clear();
+ assertEquals(0, mInstance.getDefaultValuesForTest().size());
+
+ mInstance.systemReady(/*runtimeRestarted=*/ true);
+
+ assertEquals(3, mInstance.getDefaultValuesForTest().size());
+
+ // Reset to default
+ mInstance.restoreDefault();
+ waitUntilMainHandlerDrain();
+
+ verify(mInjector, times(1)).injectWriteToFile("file1", "111");
+ verify(mInjector, times(1)).injectWriteToFile("file2", "222");
+ verify(mInjector, times(1)).injectWriteToFile("file3", "333");
+
+ // Make sure the default file still exists.
+ assertTrue(mInstance.injectDefaultValuesFilename().exists());
+
+ // Simulate a clean boot.
+ mInstance.getDefaultValuesForTest().clear();
+ assertEquals(0, mInstance.getDefaultValuesForTest().size());
+
+ mInstance.systemReady(/*runtimeRestarted=*/ false);
+
+ // Default is empty, and the file is gone.
+ assertEquals(0, mInstance.getDefaultValuesForTest().size());
+ assertFalse(mInstance.injectDefaultValuesFilename().exists());
+
+ // No WTF should have happened.
+ veriryWtf(0);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java b/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
index 7d73e82..0ea8d4f 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
@@ -1246,13 +1246,13 @@
}
private void configureUpdateAppPackageVersion(String updateAppPackageName,
- int updataAppPackageVersion) throws Exception {
+ long updataAppPackageVersion) throws Exception {
when(mMockPackageManagerHelper.getInstalledPackageVersion(updateAppPackageName))
.thenReturn(updataAppPackageVersion);
}
private void configureDataAppPackageVersion(String dataAppPackageName,
- int dataAppPackageVersion) throws Exception {
+ long dataAppPackageVersion) throws Exception {
when(mMockPackageManagerHelper.getInstalledPackageVersion(dataAppPackageName))
.thenReturn(dataAppPackageVersion);
}
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
index 39d256a..b62d724 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
@@ -16,14 +16,17 @@
package com.android.server.usage;
-import android.app.usage.AppStandby;
+import static android.app.usage.UsageStatsManager.REASON_TIMEOUT;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
+
+import android.app.usage.UsageStatsManager;
import android.os.FileUtils;
import android.test.AndroidTestCase;
import java.io.File;
-import static android.app.usage.AppStandby.*;
-
public class AppIdleHistoryTests extends AndroidTestCase {
File mStorageDir;
@@ -85,12 +88,12 @@
AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
aih.setAppStandbyBucket(PACKAGE_1, USER_ID, 1000, STANDBY_BUCKET_ACTIVE,
- AppStandby.REASON_USAGE);
+ UsageStatsManager.REASON_USAGE);
// ACTIVE means not idle
assertFalse(aih.isIdle(PACKAGE_1, USER_ID, 2000));
aih.setAppStandbyBucket(PACKAGE_2, USER_ID, 2000, STANDBY_BUCKET_ACTIVE,
- AppStandby.REASON_USAGE);
+ UsageStatsManager.REASON_USAGE);
aih.setAppStandbyBucket(PACKAGE_1, USER_ID, 3000, STANDBY_BUCKET_RARE,
REASON_TIMEOUT);
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 40edfd2..87b34ab 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -16,9 +16,12 @@
package com.android.server.usage;
-import static android.app.usage.AppStandby.*;
import static android.app.usage.UsageEvents.Event.NOTIFICATION_SEEN;
import static android.app.usage.UsageEvents.Event.USER_INTERACTION;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -30,8 +33,8 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
-import android.app.usage.AppStandby;
import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManager;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.ContextWrapper;
@@ -280,7 +283,7 @@
public void testBuckets() throws Exception {
AppStandbyController controller = setupController();
- assertTimeout(controller, 0, STANDBY_BUCKET_NEVER);
+ assertTimeout(controller, 0, UsageStatsManager.STANDBY_BUCKET_NEVER);
reportEvent(controller, USER_INTERACTION, 0);
@@ -312,7 +315,7 @@
AppStandbyController controller = setupController();
mInjector.setDisplayOn(false);
- assertTimeout(controller, 0, STANDBY_BUCKET_NEVER);
+ assertTimeout(controller, 0, UsageStatsManager.STANDBY_BUCKET_NEVER);
reportEvent(controller, USER_INTERACTION, 0);
diff --git a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
index cd3ae1a..26853a9 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
@@ -165,7 +165,7 @@
}
@Override
- public int getFactoryPackageVersion(String packageName) throws NameNotFoundException {
+ public long getFactoryPackageVersion(String packageName) throws NameNotFoundException {
PackageInfo pi = null;
Map<Integer, PackageInfo> userPackages = mPackages.get(packageName);
if (userPackages == null) throw new NameNotFoundException();
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index 2224de5..401f585 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -1512,8 +1512,8 @@
// Ensure the API is correct before running waitForAndGetProvider
assertEquals(firstPackage.packageName,
mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName);
- assertEquals(firstPackage.versionCode,
- mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionCode);
+ assertEquals(firstPackage.getLongVersionCode(),
+ mWebViewUpdateServiceImpl.getCurrentWebViewPackage().getLongVersionCode());
assertEquals(firstPackage.versionName,
mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionName);
@@ -1524,8 +1524,8 @@
// Ensure the API is still correct after running waitForAndGetProvider
assertEquals(firstPackage.packageName,
mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName);
- assertEquals(firstPackage.versionCode,
- mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionCode);
+ assertEquals(firstPackage.getLongVersionCode(),
+ mWebViewUpdateServiceImpl.getCurrentWebViewPackage().getLongVersionCode());
assertEquals(firstPackage.versionName,
mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionName);
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java b/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java
index f069d49..4dd51eb 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java
@@ -48,6 +48,10 @@
final SurfaceControl mControl = mock(SurfaceControl.class);
final SurfaceControl.Transaction mTransaction = mock(SurfaceControl.Transaction.class);
+ TestWindowContainer() {
+ super(sWm);
+ }
+
@Override
SurfaceControl getSurfaceControl() {
return mControl;
@@ -65,6 +69,10 @@
final SurfaceControl mHostControl = mock(SurfaceControl.class);
final SurfaceControl.Transaction mHostTransaction = mock(SurfaceControl.Transaction.class);
+ MockSurfaceBuildingContainer() {
+ super(sWm);
+ }
+
class MockSurfaceBuilder extends SurfaceControl.Builder {
MockSurfaceBuilder(SurfaceSession ss) {
super(ss);
@@ -78,6 +86,7 @@
}
}
+
@Override
SurfaceControl.Builder makeChildSurface(WindowContainer child) {
return new MockSurfaceBuilder(mSession);
diff --git a/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java
index 5da3224..ab0a2bd 100644
--- a/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java
@@ -34,7 +34,7 @@
* Test class for {@link StackWindowController}.
*
* Build/Install/Run:
- * bit FrameworksServicesTests:com.android.server.wm.StackWindowControllerTests
+ * atest FrameworksServicesTests:StackWindowControllerTests
*/
@SmallTest
@Presubmit
@@ -61,7 +61,6 @@
}
@Test
- @Ignore("b/65379195")
public void testRemoveContainer_deferRemoval() throws Exception {
final StackWindowController stackController =
createStackControllerOnDisplay(mDisplayContent);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
index 0a644b60..353aa7d 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
@@ -23,6 +23,7 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.MergedConfiguration;
+import android.view.DisplayCutout;
import android.view.DragEvent;
import android.view.IWindow;
@@ -37,7 +38,8 @@
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
Rect stableInsets, Rect outsets, boolean reportDraw, MergedConfiguration mergedConfig,
- Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId)
+ Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId,
+ DisplayCutout.ParcelableWrapper displayCutout)
throws RemoteException {
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index c735341..481c898 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -411,11 +411,6 @@
}
@Override
- public boolean inKeyguardRestrictedKeyInputMode() {
- return false;
- }
-
- @Override
public void dismissKeyguardLw(@Nullable IKeyguardDismissCallback callback) {
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
index 8df7568..bab2170 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
@@ -44,7 +44,7 @@
@Test
public void testCreation() throws Exception {
final WindowContainerController controller = new WindowContainerController(null, sWm);
- final WindowContainer container = new WindowContainer();
+ final WindowContainer container = new WindowContainer(sWm);
container.setController(controller);
assertEquals(controller, container.getController());
@@ -54,7 +54,7 @@
@Test
public void testSetContainer() throws Exception {
final WindowContainerController controller = new WindowContainerController(null, sWm);
- final WindowContainer container = new WindowContainer();
+ final WindowContainer container = new WindowContainer(sWm);
controller.setContainer(container);
assertEquals(controller.mContainer, container);
@@ -62,7 +62,7 @@
// Assert we can't change the container to another one once set
boolean gotException = false;
try {
- controller.setContainer(new WindowContainer());
+ controller.setContainer(new WindowContainer(sWm));
} catch (IllegalArgumentException e) {
gotException = true;
}
@@ -76,7 +76,7 @@
@Test
public void testRemoveContainer() throws Exception {
final WindowContainerController controller = new WindowContainerController(null, sWm);
- final WindowContainer container = new WindowContainer();
+ final WindowContainer container = new WindowContainer(sWm);
controller.setContainer(container);
assertEquals(controller.mContainer, container);
@@ -88,7 +88,7 @@
@Test
public void testOnOverrideConfigurationChanged() throws Exception {
final WindowContainerController controller = new WindowContainerController(null, sWm);
- final WindowContainer container = new WindowContainer();
+ final WindowContainer container = new WindowContainer(sWm);
controller.setContainer(container);
assertEquals(controller.mContainer, container);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
index 16b6ca6..5cb9467 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -193,7 +193,7 @@
@Test
public void testRemoveImmediately_WithController() throws Exception {
- final WindowContainer container = new WindowContainer();
+ final WindowContainer container = new WindowContainer(sWm);
final WindowContainerController controller = new WindowContainerController(null, sWm);
container.setController(controller);
@@ -208,7 +208,7 @@
@Test
public void testSetController() throws Exception {
final WindowContainerController controller = new WindowContainerController(null, sWm);
- final WindowContainer container = new WindowContainer();
+ final WindowContainer container = new WindowContainer(sWm);
container.setController(controller);
assertEquals(controller, container.getController());
@@ -587,6 +587,7 @@
TestWindowContainer(int layer, boolean isAnimating, boolean isVisible,
Integer orientation) {
+ super(sWm);
mLayer = layer;
mIsAnimating = isAnimating;
mIsVisible = isVisible;
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
index 503e1ac..337fd50 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -22,11 +22,12 @@
import android.app.ActivityManager.TaskDescription;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IWindow;
@@ -37,6 +38,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import java.util.Arrays;
+
/**
* Tests for the {@link WindowState#computeFrameLw} method and other window frame machinery.
*
@@ -157,7 +160,7 @@
// When mFrame extends past cf, the content insets are
// the difference between mFrame and ContentFrame. Visible
// and stable frames work the same way.
- w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null);
+ w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame,0, 0, 1000, 1000);
assertRect(w.mContentInsets, 0, topContentInset, 0, bottomContentInset);
assertRect(w.mVisibleInsets, 0, topVisibleInset, 0, bottomVisibleInset);
@@ -172,7 +175,7 @@
w.mAttrs.width = 100; w.mAttrs.height = 100; //have to clear MATCH_PARENT
w.mRequestedWidth = 100;
w.mRequestedHeight = 100;
- w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null);
+ w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, 100, 100, 200, 200);
assertRect(w.mContentInsets, 0, 0, 0, 0);
// In this case the frames are shrunk to the window frame.
@@ -193,7 +196,7 @@
// Here the window has FILL_PARENT, FILL_PARENT
// so we expect it to fill the entire available frame.
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, 0, 0, 1000, 1000);
// It can select various widths and heights within the bounds.
@@ -201,14 +204,14 @@
// and we use mRequestedWidth/mRequestedHeight
w.mAttrs.width = 300;
w.mAttrs.height = 300;
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
// Explicit width and height without requested width/height
// gets us nothing.
assertRect(w.mFrame, 0, 0, 0, 0);
w.mRequestedWidth = 300;
w.mRequestedHeight = 300;
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
// With requestedWidth/Height we can freely choose our size within the
// parent bounds.
assertRect(w.mFrame, 0, 0, 300, 300);
@@ -221,14 +224,14 @@
w.mRequestedWidth = -1;
w.mAttrs.width = 100;
w.mAttrs.height = 100;
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, 0, 0, 100, 100);
w.mAttrs.flags = 0;
// But sizes too large will be clipped to the containing frame
w.mRequestedWidth = 1200;
w.mRequestedHeight = 1200;
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, 0, 0, 1000, 1000);
// Before they are clipped though windows will be shifted
@@ -236,7 +239,7 @@
w.mAttrs.y = 300;
w.mRequestedWidth = 1000;
w.mRequestedHeight = 1000;
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, 0, 0, 1000, 1000);
// If there is room to move around in the parent frame the window will be shifted according
@@ -246,16 +249,16 @@
w.mRequestedWidth = 300;
w.mRequestedHeight = 300;
w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP;
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, 700, 0, 1000, 300);
w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM;
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, 700, 700, 1000, 1000);
// Window specified x and y are interpreted as offsets in the opposite
// direction of gravity
w.mAttrs.x = 100;
w.mAttrs.y = 100;
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, 600, 600, 900, 900);
}
@@ -276,7 +279,7 @@
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, null);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, null, DisplayCutout.NO_CUTOUT);
// For non fullscreen tasks the containing frame is based off the
// task bounds not the parent frame.
assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom);
@@ -288,7 +291,7 @@
final int cfRight = logicalWidth / 2;
final int cfBottom = logicalHeight / 2;
final Rect cf = new Rect(0, 0, cfRight, cfBottom);
- w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null);
+ w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom);
int contentInsetRight = taskRight - cfRight;
int contentInsetBottom = taskBottom - cfBottom;
@@ -305,7 +308,7 @@
final int insetRight = insetLeft + (taskRight - taskLeft);
final int insetBottom = insetTop + (taskBottom - taskTop);
task.mInsetBounds.set(insetLeft, insetTop, insetRight, insetBottom);
- w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null);
+ w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom);
contentInsetRight = insetRight - cfRight;
contentInsetBottom = insetBottom - cfBottom;
@@ -337,16 +340,13 @@
final Rect policyCrop = new Rect();
- w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null);
+ w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, DisplayCutout.NO_CUTOUT);
w.calculatePolicyCrop(policyCrop);
- // If we were above system decor we wouldnt' get any cropping though
- w.mLayer = sWm.mSystemDecorLayer + 1;
- w.calculatePolicyCrop(policyCrop);
- assertRect(policyCrop, 0, 0, logicalWidth, logicalHeight);
- w.mLayer = 1;
+ assertRect(policyCrop, 0, cf.top, logicalWidth, cf.bottom);
+
dcf.setEmpty();
// Likewise with no decor frame we would get no crop
- w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null);
+ w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, DisplayCutout.NO_CUTOUT);
w.calculatePolicyCrop(policyCrop);
assertRect(policyCrop, 0, 0, logicalWidth, logicalHeight);
@@ -359,7 +359,7 @@
w.mAttrs.height = logicalHeight / 2;
w.mRequestedWidth = logicalWidth / 2;
w.mRequestedHeight = logicalHeight / 2;
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
w.calculatePolicyCrop(policyCrop);
// Normally the crop is shrunk from the decor frame
@@ -396,7 +396,7 @@
final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
w.computeFrameLw(pf /* parentFrame */, pf /* displayFrame */, pf /* overscanFrame */,
pf /* contentFrame */, pf /* visibleFrame */, pf /* decorFrame */,
- pf /* stableFrame */, null /* outsetFrame */);
+ pf /* stableFrame */, null /* outsetFrame */, DisplayCutout.NO_CUTOUT);
// For non fullscreen tasks the containing frame is based off the
// task bounds not the parent frame.
assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom);
@@ -415,12 +415,31 @@
w.computeFrameLw(pf /* parentFrame */, pf /* displayFrame */, pf /* overscanFrame */,
cf /* contentFrame */, cf /* visibleFrame */, pf /* decorFrame */,
- cf /* stableFrame */, null /* outsetFrame */);
+ cf /* stableFrame */, null /* outsetFrame */, DisplayCutout.NO_CUTOUT);
assertEquals(cf, w.mFrame);
assertEquals(cf, w.getContentFrameLw());
assertRect(w.mContentInsets, 0, 0, 0, 0);
}
+ @Test
+ public void testDisplayCutout() {
+ // Regular fullscreen task and window
+ Task task = new TaskWithBounds(null);
+ WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
+ w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
+
+ final Rect pf = new Rect(0, 0, 1000, 1000);
+ // Create a display cutout of size 50x50, aligned top-center
+ final DisplayCutout cutout = createDisplayCutoutFromRect(500, 0, 550, 50);
+
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, cutout);
+
+ assertEquals(w.mDisplayCutout.getSafeInsetTop(), 50);
+ assertEquals(w.mDisplayCutout.getSafeInsetBottom(), 0);
+ assertEquals(w.mDisplayCutout.getSafeInsetLeft(), 0);
+ assertEquals(w.mDisplayCutout.getSafeInsetRight(), 0);
+ }
+
private WindowStateWithTask createWindow(Task task, int width, int height) {
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
attrs.width = width;
@@ -428,4 +447,13 @@
return new WindowStateWithTask(attrs, task);
}
+
+ private DisplayCutout createDisplayCutoutFromRect(int left, int top, int right, int bottom) {
+ return DisplayCutout.fromBoundingPolygon(Arrays.asList(
+ new Point(left, top),
+ new Point (left, bottom),
+ new Point (right, bottom),
+ new Point (left, bottom)
+ ));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
index f7c4b1f..6468763 100644
--- a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
@@ -16,33 +16,33 @@
package com.android.server.wm;
-import java.util.HashMap;
-import java.util.LinkedList;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import android.view.SurfaceControl;
-import android.view.SurfaceSession;
-import android.util.Log;
-
-import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
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.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+
/**
* Tests for the {@link WindowLayersController} class.
*
@@ -75,7 +75,7 @@
}
int getLayer(SurfaceControl sc) {
- return mLayersForControl.get(sc);
+ return mLayersForControl.getOrDefault(sc, 0);
}
SurfaceControl getRelativeLayer(SurfaceControl sc) {
@@ -121,6 +121,7 @@
// would miss construction of the top-level layers.
mTransaction = new LayerRecordingTransaction();
sWm.mSurfaceBuilderFactory = new HierarchyRecordingBuilderFactory();
+ sWm.mTransactionFactory = () -> mTransaction;
}
@After
@@ -185,7 +186,6 @@
// target.
assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, mDockedDividerWindow);
assertWindowLayerGreaterThan(mTransaction, mNavBarWindow, mImeWindow);
assertWindowLayerGreaterThan(mTransaction, mStatusBarWindow, mImeWindow);
@@ -324,4 +324,39 @@
assertWindowLayerGreaterThan(mTransaction, assistantStackWindow, dockedStackWindow);
assertWindowLayerGreaterThan(mTransaction, pinnedStackWindow, assistantStackWindow);
}
+
+ @Test
+ public void testAssignWindowLayers_ForSysUiPanels() throws Exception {
+ final WindowState navBarPanel =
+ createWindow(null, TYPE_NAVIGATION_BAR_PANEL, mDisplayContent, "NavBarPanel");
+ final WindowState statusBarPanel =
+ createWindow(null, TYPE_STATUS_BAR_PANEL, mDisplayContent, "StatusBarPanel");
+ final WindowState statusBarSubPanel =
+ createWindow(null, TYPE_STATUS_BAR_SUB_PANEL, mDisplayContent, "StatusBarSubPanel");
+ mDisplayContent.assignChildLayers(mTransaction);
+
+ // Ime should be above all app windows and below system windows if it is targeting an app
+ // window.
+ assertWindowLayerGreaterThan(mTransaction, navBarPanel, mNavBarWindow);
+ assertWindowLayerGreaterThan(mTransaction, statusBarPanel, mStatusBarWindow);
+ assertWindowLayerGreaterThan(mTransaction, statusBarSubPanel, statusBarPanel);
+ }
+
+ @Test
+ public void testAssignWindowLayers_ForNegativelyZOrderedSubtype() throws Exception {
+ // TODO(b/70040778): We should aim to eliminate the last user of TYPE_APPLICATION_MEDIA
+ // then we can drop all negative layering on the windowing side.
+
+ final WindowState anyWindow =
+ createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "anyWindow");
+ final WindowState child = createWindow(anyWindow, TYPE_APPLICATION_MEDIA, mDisplayContent,
+ "TypeApplicationMediaChild");
+ final WindowState mediaOverlayChild = createWindow(anyWindow, TYPE_APPLICATION_MEDIA_OVERLAY,
+ mDisplayContent, "TypeApplicationMediaOverlayChild");
+
+ mDisplayContent.assignChildLayers(mTransaction);
+
+ assertWindowLayerGreaterThan(mTransaction, anyWindow, mediaOverlayChild);
+ assertWindowLayerGreaterThan(mTransaction, mediaOverlayChild, child);
+ }
}
diff --git a/services/tests/shortcutmanagerutils/Android.mk b/services/tests/shortcutmanagerutils/Android.mk
index c7657f6..0848fd5 100644
--- a/services/tests/shortcutmanagerutils/Android.mk
+++ b/services/tests/shortcutmanagerutils/Android.mk
@@ -21,7 +21,8 @@
LOCAL_JAVA_LIBRARIES := \
mockito-target \
- legacy-android-test
+ legacy-android-test \
+ android.test.runner.stubs
LOCAL_MODULE_TAGS := optional
diff --git a/services/tests/notification/Android.mk b/services/tests/uiservicestests/Android.mk
similarity index 89%
rename from services/tests/notification/Android.mk
rename to services/tests/uiservicestests/Android.mk
index 597a584..40e7878 100644
--- a/services/tests/notification/Android.mk
+++ b/services/tests/uiservicestests/Android.mk
@@ -1,5 +1,5 @@
#########################################################################
-# Build FrameworksNotificationTests package
+# Build FrameworksUiServicesTests package
#########################################################################
LOCAL_PATH:= $(call my-dir)
@@ -25,12 +25,12 @@
platform-test-annotations \
testables
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_JACK_FLAGS := --multi-dex native
LOCAL_DX_FLAGS := --multi-dex
-LOCAL_PACKAGE_NAME := FrameworksNotificationTests
+LOCAL_PACKAGE_NAME := FrameworksUiServicesTests
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
diff --git a/services/tests/notification/AndroidManifest.xml b/services/tests/uiservicestests/AndroidManifest.xml
similarity index 91%
rename from services/tests/notification/AndroidManifest.xml
rename to services/tests/uiservicestests/AndroidManifest.xml
index c20020a..621b457 100644
--- a/services/tests/notification/AndroidManifest.xml
+++ b/services/tests/uiservicestests/AndroidManifest.xml
@@ -15,7 +15,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.frameworks.tests.notification">
+ package="com.android.frameworks.tests.uiservices">
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
@@ -32,6 +32,6 @@
<instrumentation
android:name="android.testing.TestableInstrumentation"
- android:targetPackage="com.android.frameworks.tests.notification"
+ android:targetPackage="com.android.frameworks.tests.uiservices"
android:label="Notification Tests" />
</manifest>
diff --git a/services/tests/notification/AndroidTest.xml b/services/tests/uiservicestests/AndroidTest.xml
similarity index 82%
rename from services/tests/notification/AndroidTest.xml
rename to services/tests/uiservicestests/AndroidTest.xml
index 448bc3d..d3b9d4a 100644
--- a/services/tests/notification/AndroidTest.xml
+++ b/services/tests/uiservicestests/AndroidTest.xml
@@ -13,16 +13,16 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<configuration description="Runs Frameworks Notification Tests.">
+<configuration description="Runs Frameworks UI Services Tests.">
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
- <option name="test-file-name" value="FrameworksNotificationTests.apk" />
+ <option name="test-file-name" value="FrameworksUiServicesTests.apk" />
</target_preparer>
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="framework-base-presubmit" />
- <option name="test-tag" value="FrameworksNotificationTests" />
+ <option name="test-tag" value="FrameworksUiServicesTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="com.android.frameworks.tests.notification" />
+ <option name="package" value="com.android.frameworks.tests.uiservices" />
<option name="runner" value="android.testing.TestableInstrumentation" />
</test>
</configuration>
diff --git a/services/tests/notification/src/com/android/server/notification/AlertRateLimiterTest.java b/services/tests/uiservicestests/src/com/android/server/notification/AlertRateLimiterTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/AlertRateLimiterTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/AlertRateLimiterTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/ManagedServicesTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationChannelExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/NotificationChannelExtractorTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationChannelTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/NotificationChannelTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/NotificationListenerServiceTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationStatsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationStatsTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/NotificationStatsTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationStatsTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/NotificationTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationTestCase.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTestCase.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/NotificationTestCase.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationTestCase.java
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/RateEstimatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RateEstimatorTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/RateEstimatorTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/RateEstimatorTest.java
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
new file mode 100644
index 0000000..4eb4220
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
@@ -0,0 +1,327 @@
+/*
+ * 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.notification;
+
+import static junit.framework.Assert.assertFalse;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.service.notification.ScheduleCalendar;
+import android.service.notification.ZenModeConfig;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ScheduleCalendarTest extends NotificationTestCase {
+
+ private ScheduleCalendar mScheduleCalendar;
+ private ZenModeConfig.ScheduleInfo mScheduleInfo;
+
+ @Before
+ public void setUp() throws Exception {
+ mScheduleCalendar = new ScheduleCalendar();
+ mScheduleInfo = new ZenModeConfig.ScheduleInfo();
+ mScheduleInfo.days = new int[] {1, 2, 3, 4, 5};
+ mScheduleCalendar.setSchedule(mScheduleInfo);
+ }
+
+ @Test
+ public void testNullScheduleInfo() throws Exception {
+ mScheduleCalendar.setSchedule(null);
+
+ mScheduleCalendar.maybeSetNextAlarm(1000, 1999);
+ assertEquals(0, mScheduleCalendar.getNextChangeTime(1000));
+ assertFalse(mScheduleCalendar.isInSchedule(100));
+ assertFalse(mScheduleCalendar.shouldExitForAlarm(100));
+ }
+
+ @Test
+ public void testGetNextChangeTime_startToday() throws Exception {
+ Calendar cal = new GregorianCalendar();
+ cal.set(Calendar.HOUR_OF_DAY, 1);
+ cal.set(Calendar.MINUTE, 15);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ mScheduleInfo.days = new int[] {getTodayDay()};
+ mScheduleInfo.startHour = cal.get(Calendar.HOUR_OF_DAY) + 1;
+ mScheduleInfo.endHour = cal.get(Calendar.HOUR_OF_DAY) + 3;
+ mScheduleInfo.startMinute = 15;
+ mScheduleInfo.endMinute = 15;
+ mScheduleInfo.exitAtAlarm = false;
+ mScheduleCalendar.setSchedule(mScheduleInfo);
+
+ Calendar expected = new GregorianCalendar();
+ expected.setTimeInMillis(cal.getTimeInMillis());
+ expected.set(Calendar.HOUR_OF_DAY, mScheduleInfo.startHour);
+
+ long actualMs = mScheduleCalendar.getNextChangeTime(cal.getTimeInMillis());
+ GregorianCalendar actual = new GregorianCalendar();
+ actual.setTimeInMillis(actualMs);
+ assertEquals("Expected " + expected + " was " + actual, expected.getTimeInMillis(),
+ actualMs);
+ }
+
+ @Test
+ public void testGetNextChangeTime_endToday() throws Exception {
+ Calendar cal = new GregorianCalendar();
+ cal.set(Calendar.HOUR_OF_DAY, 2);
+ cal.set(Calendar.MINUTE, 15);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ mScheduleInfo.days = new int[] {getTodayDay()};
+ mScheduleInfo.startHour = cal.get(Calendar.HOUR_OF_DAY) - 1;
+ mScheduleInfo.endHour = cal.get(Calendar.HOUR_OF_DAY) + 3;
+ mScheduleInfo.startMinute = 15;
+ mScheduleInfo.endMinute = 15;
+ mScheduleInfo.exitAtAlarm = false;
+
+ Calendar expected = new GregorianCalendar();
+ expected.setTimeInMillis(cal.getTimeInMillis());
+ expected.set(Calendar.HOUR_OF_DAY, mScheduleInfo.endHour);
+ expected.set(Calendar.MINUTE, mScheduleInfo.endMinute);
+
+ long actualMs = mScheduleCalendar.getNextChangeTime(cal.getTimeInMillis());
+ GregorianCalendar actual = new GregorianCalendar();
+ actual.setTimeInMillis(actualMs);
+ assertEquals("Expected " + expected + " was " + actual, expected.getTimeInMillis(),
+ actualMs);
+ }
+
+ @Test
+ public void testGetNextChangeTime_startTomorrow() throws Exception {
+ Calendar cal = new GregorianCalendar();
+ cal.set(Calendar.HOUR_OF_DAY, 23);
+ cal.set(Calendar.MINUTE, 15);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay() + 1};
+ mScheduleInfo.startHour = 1;
+ mScheduleInfo.endHour = 3;
+ mScheduleInfo.startMinute = 15;
+ mScheduleInfo.endMinute = 15;
+ mScheduleInfo.exitAtAlarm = false;
+
+ Calendar expected = new GregorianCalendar();
+ expected.setTimeInMillis(cal.getTimeInMillis());
+ expected.add(Calendar.DATE, 1);
+ expected.set(Calendar.HOUR_OF_DAY, mScheduleInfo.startHour);
+ expected.set(Calendar.MINUTE, mScheduleInfo.startMinute);
+
+ long actualMs = mScheduleCalendar.getNextChangeTime(cal.getTimeInMillis());
+ GregorianCalendar actual = new GregorianCalendar();
+ actual.setTimeInMillis(actualMs);
+ assertEquals("Expected " + expected + " was " + actual, expected.getTimeInMillis(),
+ actualMs);
+ }
+
+ @Test
+ public void testGetNextChangeTime_endTomorrow() throws Exception {
+ Calendar cal = new GregorianCalendar();
+ cal.set(Calendar.HOUR_OF_DAY, 23);
+ cal.set(Calendar.MINUTE, 15);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay() + 1};
+ mScheduleInfo.startHour = 22;
+ mScheduleInfo.endHour = 3;
+ mScheduleInfo.startMinute = 15;
+ mScheduleInfo.endMinute = 15;
+ mScheduleInfo.exitAtAlarm = false;
+
+ Calendar expected = new GregorianCalendar();
+ expected.setTimeInMillis(cal.getTimeInMillis());
+ expected.add(Calendar.DATE, 1);
+ expected.set(Calendar.HOUR_OF_DAY, mScheduleInfo.endHour);
+ expected.set(Calendar.MINUTE, mScheduleInfo.endMinute);
+
+ long actualMs = mScheduleCalendar.getNextChangeTime(cal.getTimeInMillis());
+ GregorianCalendar actual = new GregorianCalendar();
+ actual.setTimeInMillis(actualMs);
+ assertEquals("Expected " + expected + " was " + actual, expected.getTimeInMillis(),
+ actualMs);
+ }
+
+ @Test
+ public void testShouldExitForAlarm_settingOff() {
+ mScheduleInfo.exitAtAlarm = false;
+ mScheduleInfo.nextAlarm = 1000;
+
+ assertFalse(mScheduleCalendar.shouldExitForAlarm(1000));
+ }
+
+ @Test
+ public void testShouldExitForAlarm_beforeAlarm() {
+ mScheduleInfo.exitAtAlarm = true;
+ mScheduleInfo.nextAlarm = 1000;
+
+ assertFalse(mScheduleCalendar.shouldExitForAlarm(999));
+ }
+
+ @Test
+ public void testShouldExitForAlarm_noAlarm() {
+ mScheduleInfo.exitAtAlarm = true;
+ mScheduleInfo.nextAlarm = 0;
+
+ assertFalse(mScheduleCalendar.shouldExitForAlarm(999));
+ }
+
+ @Test
+ public void testShouldExitForAlarm() {
+ mScheduleInfo.exitAtAlarm = true;
+ mScheduleInfo.nextAlarm = 1000;
+
+ assertTrue(mScheduleCalendar.shouldExitForAlarm(1000));
+ }
+
+ @Test
+ public void testMaybeSetNextAlarm_settingOff() {
+ mScheduleInfo.exitAtAlarm = false;
+ mScheduleInfo.nextAlarm = 0;
+
+ mScheduleCalendar.maybeSetNextAlarm(1000, 2000);
+
+ assertEquals(0, mScheduleInfo.nextAlarm);
+ }
+
+ @Test
+ public void testMaybeSetNextAlarm_settingOn() {
+ mScheduleInfo.exitAtAlarm = true;
+ mScheduleInfo.nextAlarm = 0;
+
+ mScheduleCalendar.maybeSetNextAlarm(1000, 2000);
+
+ assertEquals(2000, mScheduleInfo.nextAlarm);
+ }
+
+ @Test
+ public void testMaybeSetNextAlarm_alarmCanceled() {
+ mScheduleInfo.exitAtAlarm = true;
+ mScheduleInfo.nextAlarm = 10000;
+
+ mScheduleCalendar.maybeSetNextAlarm(1000, 0);
+
+ assertEquals(0, mScheduleInfo.nextAlarm);
+ }
+
+ @Test
+ public void testMaybeSetNextAlarm_earlierAlarm() {
+ mScheduleInfo.exitAtAlarm = true;
+ mScheduleInfo.nextAlarm = 2000;
+
+ mScheduleCalendar.maybeSetNextAlarm(1000, 1500);
+
+ assertEquals(1500, mScheduleInfo.nextAlarm);
+ }
+
+ @Test
+ public void testMaybeSetNextAlarm_laterAlarm() {
+ mScheduleInfo.exitAtAlarm = true;
+ mScheduleInfo.nextAlarm = 2000;
+
+ mScheduleCalendar.maybeSetNextAlarm(1000, 3000);
+
+ assertEquals(2000, mScheduleInfo.nextAlarm);
+ }
+
+ @Test
+ public void testMaybeSetNextAlarm_expiredAlarm() {
+ mScheduleInfo.exitAtAlarm = true;
+ mScheduleInfo.nextAlarm = 998;
+
+ mScheduleCalendar.maybeSetNextAlarm(1000, 999);
+
+ assertEquals(0, mScheduleInfo.nextAlarm);
+ }
+
+ @Test
+ public void testIsInSchedule_inScheduleOvernight() {
+ Calendar cal = new GregorianCalendar();
+ cal.set(Calendar.HOUR_OF_DAY, 23);
+ cal.set(Calendar.MINUTE, 15);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ mScheduleInfo.days = new int[] {getTodayDay()};
+ mScheduleInfo.startHour = 22;
+ mScheduleInfo.endHour = 3;
+ mScheduleInfo.startMinute = 15;
+ mScheduleInfo.endMinute = 15;
+
+ assertTrue(mScheduleCalendar.isInSchedule(cal.getTimeInMillis()));
+ }
+
+ @Test
+ public void testIsInSchedule_inScheduleSingleDay() {
+ Calendar cal = new GregorianCalendar();
+ cal.set(Calendar.HOUR_OF_DAY, 14);
+ cal.set(Calendar.MINUTE, 15);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ mScheduleInfo.days = new int[] {getTodayDay()};
+ mScheduleInfo.startHour = 12;
+ mScheduleInfo.endHour = 3;
+ mScheduleInfo.startMinute = 16;
+ mScheduleInfo.endMinute = 15;
+
+ assertTrue(mScheduleCalendar.isInSchedule(cal.getTimeInMillis()));
+ }
+
+ @Test
+ public void testIsInSchedule_notToday() {
+ Calendar cal = new GregorianCalendar();
+ cal.set(Calendar.HOUR_OF_DAY, 14);
+ cal.set(Calendar.MINUTE, 15);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ cal.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
+ mScheduleInfo.days = new int[] {Calendar.FRIDAY, Calendar.SUNDAY};
+ mScheduleInfo.startHour = 12;
+ mScheduleInfo.startMinute = 16;
+ mScheduleInfo.endHour = 15;
+ mScheduleInfo.endMinute = 15;
+
+ assertFalse(mScheduleCalendar.isInSchedule(cal.getTimeInMillis()));
+ }
+
+ @Test
+ public void testIsInSchedule_startingSoon() {
+ Calendar cal = new GregorianCalendar();
+ cal.set(Calendar.HOUR_OF_DAY, 14);
+ cal.set(Calendar.MINUTE, 15);
+ cal.set(Calendar.SECOND, 59);
+ cal.set(Calendar.MILLISECOND, 0);
+ mScheduleInfo.days = new int[] {getTodayDay()};
+ mScheduleInfo.startHour = 14;
+ mScheduleInfo.endHour = 3;
+ mScheduleInfo.startMinute = 16;
+ mScheduleInfo.endMinute = 15;
+
+ assertFalse(mScheduleCalendar.isInSchedule(cal.getTimeInMillis()));
+ }
+
+ private int getTodayDay() {
+ return new GregorianCalendar().get(Calendar.DAY_OF_WEEK);
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleConditionProviderTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleConditionProviderTest.java
new file mode 100644
index 0000000..610592f
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleConditionProviderTest.java
@@ -0,0 +1,342 @@
+package com.android.server.notification;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.spy;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.service.notification.Condition;
+import android.service.notification.ScheduleCalendar;
+import android.service.notification.ZenModeConfig;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ScheduleConditionProviderTest extends NotificationTestCase {
+
+ ScheduleConditionProvider mService;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ Intent startIntent =
+ new Intent("com.android.server.notification.ScheduleConditionProvider");
+ startIntent.setPackage("android");
+ ScheduleConditionProvider service = new ScheduleConditionProvider();
+ service.attach(
+ getContext(),
+ null, // ActivityThread not actually used in Service
+ ScheduleConditionProvider.class.getName(),
+ null, // token not needed when not talking with the activity manager
+ null,
+ null // mocked services don't talk with the activity manager
+ );
+ service.onCreate();
+ service.onBind(startIntent);
+ mService = spy(service);
+ }
+
+ @Test
+ public void testIsValidConditionId_incomplete() throws Exception {
+ Uri badConditionId = Uri.EMPTY;
+ assertFalse(mService.isValidConditionId(badConditionId));
+ assertEquals(Condition.STATE_ERROR,
+ mService.evaluateSubscriptionLocked(badConditionId, null, 0, 1000).state);
+ }
+
+ @Test
+ public void testIsValidConditionId() throws Exception {
+ ZenModeConfig.ScheduleInfo info = new ZenModeConfig.ScheduleInfo();
+ info.days = new int[] {1, 2, 4};
+ info.startHour = 8;
+ info.startMinute = 56;
+ info.nextAlarm = 1000;
+ info.exitAtAlarm = true;
+ info.endHour = 12;
+ info.endMinute = 9;
+ Uri conditionId = ZenModeConfig.toScheduleConditionId(info);
+ assertTrue(mService.isValidConditionId(conditionId));
+ }
+
+ @Test
+ public void testEvaluateSubscription_noAlarmExit_InSchedule() {
+ Calendar now = getNow();
+
+ // Schedule - 1 hour long; starts now
+ ZenModeConfig.ScheduleInfo info = new ZenModeConfig.ScheduleInfo();
+ info.days = new int[] {Calendar.FRIDAY};
+ info.startHour = now.get(Calendar.HOUR_OF_DAY);
+ info.startMinute = now.get(Calendar.MINUTE);
+ info.nextAlarm = 0;
+ info.exitAtAlarm = false;
+ info.endHour = now.get(Calendar.HOUR_OF_DAY) + 1;
+ info.endMinute = info.startMinute;
+ Uri conditionId = ZenModeConfig.toScheduleConditionId(info);
+ ScheduleCalendar cal = new ScheduleCalendar();
+ cal.setSchedule(info);
+ assertTrue(cal.isInSchedule(now.getTimeInMillis()));
+
+ Condition condition = mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis(), now.getTimeInMillis() + 1000);
+
+ assertEquals(Condition.STATE_TRUE, condition.state);
+ }
+
+ @Test
+ public void testEvaluateSubscription_noAlarmExit_InScheduleSnoozed() {
+ Calendar now = getNow();
+
+ // Schedule - 1 hour long; starts now
+ ZenModeConfig.ScheduleInfo info = new ZenModeConfig.ScheduleInfo();
+ info.days = new int[] {Calendar.FRIDAY};
+ info.startHour = now.get(Calendar.HOUR_OF_DAY);
+ info.startMinute = now.get(Calendar.MINUTE);
+ info.nextAlarm = 0;
+ info.exitAtAlarm = false;
+ info.endHour = now.get(Calendar.HOUR_OF_DAY) + 1;
+ info.endMinute = info.startMinute;
+ Uri conditionId = ZenModeConfig.toScheduleConditionId(info);
+ ScheduleCalendar cal = new ScheduleCalendar();
+ cal.setSchedule(info);
+ assertTrue(cal.isInSchedule(now.getTimeInMillis()));
+
+ mService.addSnoozed(conditionId);
+
+ Condition condition = mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis(), now.getTimeInMillis() + 1000);
+
+ assertEquals(Condition.STATE_FALSE, condition.state);
+ }
+
+ @Test
+ public void testEvaluateSubscription_noAlarmExit_beforeSchedule() {
+ Calendar now = new GregorianCalendar();
+ now.set(Calendar.HOUR_OF_DAY, 14);
+ now.set(Calendar.MINUTE, 15);
+ now.set(Calendar.SECOND, 59);
+ now.set(Calendar.MILLISECOND, 0);
+ now.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
+
+ // Schedule - 1 hour long; starts in 1 second
+ ZenModeConfig.ScheduleInfo info = new ZenModeConfig.ScheduleInfo();
+ info.days = new int[] {Calendar.FRIDAY};
+ info.startHour = now.get(Calendar.HOUR_OF_DAY);
+ info.startMinute = now.get(Calendar.MINUTE) + 1;
+ info.nextAlarm = 0;
+ info.exitAtAlarm = false;
+ info.endHour = now.get(Calendar.HOUR_OF_DAY) + 1;
+ info.endMinute = info.startMinute;
+ Uri conditionId = ZenModeConfig.toScheduleConditionId(info);
+ ScheduleCalendar cal = new ScheduleCalendar();
+ cal.setSchedule(info);
+
+ Condition condition = mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis(), now.getTimeInMillis() + 1000);
+
+ assertEquals(Condition.STATE_FALSE, condition.state);
+ }
+
+ @Test
+ public void testEvaluateSubscription_noAlarmExit_endSchedule() {
+ Calendar now = getNow();
+
+ // Schedule - 1 hour long; ends now
+ ZenModeConfig.ScheduleInfo info = new ZenModeConfig.ScheduleInfo();
+ info.days = new int[] {Calendar.FRIDAY};
+ info.startHour = now.get(Calendar.HOUR_OF_DAY) - 1;
+ info.startMinute = now.get(Calendar.MINUTE);
+ info.nextAlarm = 0;
+ info.exitAtAlarm = false;
+ info.endHour = now.get(Calendar.HOUR_OF_DAY);
+ info.endMinute = now.get(Calendar.MINUTE);
+ Uri conditionId = ZenModeConfig.toScheduleConditionId(info);
+ ScheduleCalendar cal = new ScheduleCalendar();
+ cal.setSchedule(info);
+
+ Condition condition = mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis(), now.getTimeInMillis() + 1000);
+
+ assertEquals(Condition.STATE_FALSE, condition.state);
+ }
+
+ @Test
+ public void testEvaluateSubscription_alarmSetBeforeInSchedule() {
+ Calendar now = getNow();
+
+ // Schedule - 1 hour long; starts now, ends with alarm
+ ZenModeConfig.ScheduleInfo info = getScheduleEndsInHour(now);
+ Uri conditionId = ZenModeConfig.toScheduleConditionId(info);
+ ScheduleCalendar cal = new ScheduleCalendar();
+ cal.setSchedule(info);
+
+ // an hour before start, update with an alarm that will fire during the schedule
+ mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis() - 1000, now.getTimeInMillis() + 1000);
+
+ // at start, should be in dnd
+ Condition condition = mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis(), now.getTimeInMillis() + 1000);
+ assertEquals(Condition.STATE_TRUE, condition.state);
+
+ // at alarm fire time, should exit dnd
+ assertTrue(cal.isInSchedule(now.getTimeInMillis() + 1000));
+ assertTrue("" + info.nextAlarm + " " + now.getTimeInMillis(),
+ cal.shouldExitForAlarm(now.getTimeInMillis() + 1000));
+ condition = mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis() + 1000, 0);
+ assertEquals(Condition.STATE_FALSE, condition.state);
+ }
+
+ @Test
+ public void testEvaluateSubscription_alarmSetInSchedule() {
+ Calendar now = getNow();
+
+ // Schedule - 1 hour long; starts now, ends with alarm
+ ZenModeConfig.ScheduleInfo info = getScheduleEndsInHour(now);
+ Uri conditionId = ZenModeConfig.toScheduleConditionId(info);
+ ScheduleCalendar cal = new ScheduleCalendar();
+ cal.setSchedule(info);
+
+ // at start, should be in dnd
+ Condition condition = mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis(), 0);
+ assertEquals(Condition.STATE_TRUE, condition.state);
+
+ // in schedule, update with alarm time, should be in dnd
+ condition = mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis() + 500, now.getTimeInMillis() + 1000);
+ assertEquals(Condition.STATE_TRUE, condition.state);
+
+ // at alarm fire time, should exit dnd
+ assertTrue(cal.isInSchedule(now.getTimeInMillis() + 1000));
+ assertTrue("" + info.nextAlarm + " " + now.getTimeInMillis(),
+ cal.shouldExitForAlarm(now.getTimeInMillis() + 1000));
+ condition = mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis() + 1000, 0);
+ assertEquals(Condition.STATE_FALSE, condition.state);
+ }
+
+ @Test
+ public void testEvaluateSubscription_earlierAlarmSet() {
+ Calendar now = getNow();
+
+ // Schedule - 1 hour long; starts now, ends with alarm
+ ZenModeConfig.ScheduleInfo info = getScheduleEndsInHour(now);
+ Uri conditionId = ZenModeConfig.toScheduleConditionId(info);
+ ScheduleCalendar cal = new ScheduleCalendar();
+ cal.setSchedule(info);
+
+ // at start, should be in dnd, alarm in 2000 ms
+ Condition condition = mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis(), now.getTimeInMillis() + 2000);
+ assertEquals(Condition.STATE_TRUE, condition.state);
+
+ // in schedule, update with earlier alarm time, should be in dnd
+ condition = mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis() + 500, now.getTimeInMillis() + 1000);
+ assertEquals(Condition.STATE_TRUE, condition.state);
+
+ // at earliest alarm fire time, should exit dnd
+ assertTrue(cal.isInSchedule(now.getTimeInMillis() + 1000));
+ assertTrue("" + info.nextAlarm + " " + now.getTimeInMillis(),
+ cal.shouldExitForAlarm(now.getTimeInMillis() + 1000));
+ condition = mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis() + 1000, 0);
+ assertEquals(Condition.STATE_FALSE, condition.state);
+ }
+
+ @Test
+ public void testEvaluateSubscription_laterAlarmSet() {
+ Calendar now = getNow();
+
+ // Schedule - 1 hour long; starts now, ends with alarm
+ ZenModeConfig.ScheduleInfo info = getScheduleEndsInHour(now);
+ Uri conditionId = ZenModeConfig.toScheduleConditionId(info);
+ ScheduleCalendar cal = new ScheduleCalendar();
+ cal.setSchedule(info);
+
+ // at start, should be in dnd, alarm in 500 ms
+ Condition condition = mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis(), now.getTimeInMillis() + 500);
+ assertEquals(Condition.STATE_TRUE, condition.state);
+
+ // in schedule, update with later alarm time, should be in dnd
+ condition = mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis() + 250, now.getTimeInMillis() + 1000);
+ assertEquals(Condition.STATE_TRUE, condition.state);
+
+ // at earliest alarm fire time, should exit dnd
+ assertTrue(cal.isInSchedule(now.getTimeInMillis() + 500));
+ assertTrue("" + info.nextAlarm + " " + now.getTimeInMillis(),
+ cal.shouldExitForAlarm(now.getTimeInMillis() + 500));
+ condition = mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis() + 500, 0);
+ assertEquals(Condition.STATE_FALSE, condition.state);
+ }
+
+ @Test
+ public void testEvaluateSubscription_alarmCanceled() {
+ Calendar now = getNow();
+
+ // Schedule - 1 hour long; starts now, ends with alarm
+ ZenModeConfig.ScheduleInfo info = getScheduleEndsInHour(now);
+ Uri conditionId = ZenModeConfig.toScheduleConditionId(info);
+ ScheduleCalendar cal = new ScheduleCalendar();
+ cal.setSchedule(info);
+
+ // at start, should be in dnd, alarm in 500 ms
+ Condition condition = mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis(), now.getTimeInMillis() + 500);
+ assertEquals(Condition.STATE_TRUE, condition.state);
+
+ // in schedule, cancel alarm
+ condition = mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis() + 250, 0);
+ assertEquals(Condition.STATE_TRUE, condition.state);
+
+ // at previous alarm time, should not exit DND
+ assertTrue(cal.isInSchedule(now.getTimeInMillis() + 500));
+ assertFalse(cal.shouldExitForAlarm(now.getTimeInMillis() + 500));
+ condition = mService.evaluateSubscriptionLocked(
+ conditionId, cal, now.getTimeInMillis() + 500, 0);
+ assertEquals(Condition.STATE_TRUE, condition.state);
+
+ // end of schedule, exit DND
+ now.add(Calendar.HOUR_OF_DAY, 1);
+ condition = mService.evaluateSubscriptionLocked(conditionId, cal, now.getTimeInMillis(), 0);
+ assertEquals(Condition.STATE_FALSE, condition.state);
+ }
+
+ private Calendar getNow() {
+ Calendar now = new GregorianCalendar();
+ now.set(Calendar.HOUR_OF_DAY, 14);
+ now.set(Calendar.MINUTE, 16);
+ now.set(Calendar.SECOND, 0);
+ now.set(Calendar.MILLISECOND, 0);
+ now.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
+ return now;
+ }
+
+ private ZenModeConfig.ScheduleInfo getScheduleEndsInHour(Calendar now) {
+ ZenModeConfig.ScheduleInfo info = new ZenModeConfig.ScheduleInfo();
+ info.days = new int[] {Calendar.FRIDAY};
+ info.startHour = now.get(Calendar.HOUR_OF_DAY);
+ info.startMinute = now.get(Calendar.MINUTE);
+ info.exitAtAlarm = true;
+ info.endHour = now.get(Calendar.HOUR_OF_DAY) + 1;
+ info.endMinute = now.get(Calendar.MINUTE);
+ return info;
+ }
+}
diff --git a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/ValidateNotificationPeopleTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/ValidateNotificationPeopleTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
diff --git a/services/tests/notification/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
similarity index 100%
rename from services/tests/notification/src/com/android/server/notification/ZenModeHelperTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index ee11241..5aef55b 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -16,10 +16,7 @@
package com.android.server.usage;
-import static android.app.usage.AppStandby.*;
-
-import android.app.usage.AppStandby;
-import android.os.Environment;
+import android.app.usage.UsageStatsManager;
import android.os.SystemClock;
import android.util.ArrayMap;
import android.util.AtomicFile;
@@ -99,7 +96,8 @@
final byte[] recent = new byte[HISTORY_SIZE];
long lastUsedElapsedTime;
long lastUsedScreenTime;
- @StandbyBuckets int currentBucket;
+ @UsageStatsManager.StandbyBuckets
+ int currentBucket;
String bucketingReason;
int lastInformedBucket;
}
@@ -190,14 +188,14 @@
+ (elapsedRealtime - mElapsedSnapshot);
appUsageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
appUsageHistory.recent[HISTORY_SIZE - 1] = FLAG_LAST_STATE | FLAG_PARTIAL_ACTIVE;
- if (appUsageHistory.currentBucket > STANDBY_BUCKET_ACTIVE) {
- appUsageHistory.currentBucket = STANDBY_BUCKET_ACTIVE;
+ if (appUsageHistory.currentBucket > UsageStatsManager.STANDBY_BUCKET_ACTIVE) {
+ appUsageHistory.currentBucket = UsageStatsManager.STANDBY_BUCKET_ACTIVE;
if (DEBUG) {
Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory.currentBucket
+ ", reason=" + appUsageHistory.bucketingReason);
}
}
- appUsageHistory.bucketingReason = AppStandby.REASON_USAGE;
+ appUsageHistory.bucketingReason = UsageStatsManager.REASON_USAGE;
return appUsageHistory.currentBucket;
}
@@ -206,15 +204,15 @@
ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName,
elapsedRealtime, true);
- if (appUsageHistory.currentBucket > STANDBY_BUCKET_WORKING_SET) {
- appUsageHistory.currentBucket = STANDBY_BUCKET_WORKING_SET;
+ if (appUsageHistory.currentBucket > UsageStatsManager.STANDBY_BUCKET_WORKING_SET) {
+ appUsageHistory.currentBucket = UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
if (DEBUG) {
Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory.currentBucket
+ ", reason=" + appUsageHistory.bucketingReason);
}
}
// TODO: Should this be a different reason for partial usage?
- appUsageHistory.bucketingReason = AppStandby.REASON_USAGE;
+ appUsageHistory.bucketingReason = UsageStatsManager.REASON_USAGE;
return appUsageHistory.currentBucket;
}
@@ -271,8 +269,9 @@
appUsageHistory = new AppUsageHistory();
appUsageHistory.lastUsedElapsedTime = getElapsedTime(elapsedRealtime);
appUsageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
- appUsageHistory.currentBucket = AppStandby.STANDBY_BUCKET_NEVER;
- appUsageHistory.bucketingReason = REASON_DEFAULT;
+ appUsageHistory.currentBucket = UsageStatsManager.STANDBY_BUCKET_NEVER;
+ appUsageHistory.bucketingReason = UsageStatsManager.REASON_DEFAULT;
+ appUsageHistory.lastInformedBucket = -1;
userHistory.put(packageName, appUsageHistory);
}
return appUsageHistory;
@@ -289,7 +288,7 @@
if (appUsageHistory == null) {
return false; // Default to not idle
} else {
- return appUsageHistory.currentBucket >= AppStandby.STANDBY_BUCKET_RARE;
+ return appUsageHistory.currentBucket >= UsageStatsManager.STANDBY_BUCKET_RARE;
// Whether or not it's passed will now be externally calculated and the
// bucket will be pushed to the history using setAppStandbyBucket()
//return hasPassedThresholds(appUsageHistory, elapsedRealtime);
@@ -333,12 +332,12 @@
AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName,
elapsedRealtime, true);
if (idle) {
- appUsageHistory.currentBucket = STANDBY_BUCKET_RARE;
- appUsageHistory.bucketingReason = REASON_FORCED;
+ appUsageHistory.currentBucket = UsageStatsManager.STANDBY_BUCKET_RARE;
+ appUsageHistory.bucketingReason = UsageStatsManager.REASON_FORCED;
} else {
- appUsageHistory.currentBucket = STANDBY_BUCKET_ACTIVE;
+ appUsageHistory.currentBucket = UsageStatsManager.STANDBY_BUCKET_ACTIVE;
// This is to pretend that the app was just used, don't freeze the state anymore.
- appUsageHistory.bucketingReason = REASON_USAGE;
+ appUsageHistory.bucketingReason = UsageStatsManager.REASON_USAGE;
}
return appUsageHistory.currentBucket;
}
@@ -435,12 +434,12 @@
String currentBucketString = parser.getAttributeValue(null,
ATTR_CURRENT_BUCKET);
appUsageHistory.currentBucket = currentBucketString == null
- ? AppStandby.STANDBY_BUCKET_ACTIVE
+ ? UsageStatsManager.STANDBY_BUCKET_ACTIVE
: Integer.parseInt(currentBucketString);
appUsageHistory.bucketingReason =
parser.getAttributeValue(null, ATTR_BUCKETING_REASON);
if (appUsageHistory.bucketingReason == null) {
- appUsageHistory.bucketingReason = REASON_DEFAULT;
+ appUsageHistory.bucketingReason = UsageStatsManager.REASON_DEFAULT;
}
userHistory.put(packageName, appUsageHistory);
}
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 3c099c2..3d20a64 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -16,15 +16,25 @@
package com.android.server.usage;
+import static android.app.usage.UsageStatsManager.REASON_DEFAULT;
+import static android.app.usage.UsageStatsManager.REASON_FORCED;
+import static android.app.usage.UsageStatsManager.REASON_TIMEOUT;
+import static android.app.usage.UsageStatsManager.REASON_USAGE;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
+
import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.admin.DevicePolicyManager;
-import android.app.usage.AppStandby;
-import android.app.usage.AppStandby.StandbyBuckets;
+import android.app.usage.UsageStatsManager.StandbyBuckets;
import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
@@ -102,10 +112,10 @@
};
static final int[] THRESHOLD_BUCKETS = {
- AppStandby.STANDBY_BUCKET_ACTIVE,
- AppStandby.STANDBY_BUCKET_WORKING_SET,
- AppStandby.STANDBY_BUCKET_FREQUENT,
- AppStandby.STANDBY_BUCKET_RARE
+ STANDBY_BUCKET_ACTIVE,
+ STANDBY_BUCKET_WORKING_SET,
+ STANDBY_BUCKET_FREQUENT,
+ STANDBY_BUCKET_RARE
};
// To name the lock for stack traces
@@ -370,19 +380,24 @@
Slog.d(TAG, " Checking idle state for " + packageName);
}
if (isSpecial) {
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
+ STANDBY_BUCKET_EXEMPTED, REASON_DEFAULT);
+ }
maybeInformListeners(packageName, userId, elapsedRealtime,
- AppStandby.STANDBY_BUCKET_ACTIVE);
+ STANDBY_BUCKET_EXEMPTED);
} else {
synchronized (mAppIdleLock) {
String bucketingReason = mAppIdleHistory.getAppStandbyReason(packageName,
userId, elapsedRealtime);
// If the bucket was forced by the developer, leave it alone
- if (AppStandby.REASON_FORCED.equals(bucketingReason)) {
+ if (REASON_FORCED.equals(bucketingReason)) {
continue;
}
// If the bucket was moved up due to usage, let the timeouts apply.
- if (AppStandby.REASON_USAGE.equals(bucketingReason)
- || AppStandby.REASON_TIMEOUT.equals(bucketingReason)) {
+ if (REASON_DEFAULT.equals(bucketingReason)
+ || REASON_USAGE.equals(bucketingReason)
+ || REASON_TIMEOUT.equals(bucketingReason)) {
int oldBucket = mAppIdleHistory.getAppStandbyBucket(packageName, userId,
elapsedRealtime);
int newBucket = getBucketForLocked(packageName, userId,
@@ -393,7 +408,7 @@
}
if (oldBucket < newBucket) {
mAppIdleHistory.setAppStandbyBucket(packageName, userId,
- elapsedRealtime, newBucket, AppStandby.REASON_TIMEOUT);
+ elapsedRealtime, newBucket, REASON_TIMEOUT);
maybeInformListeners(packageName, userId, elapsedRealtime,
newBucket);
}
@@ -742,7 +757,7 @@
long elapsedRealtime, boolean shouldObfuscateInstantApps) {
if (shouldObfuscateInstantApps &&
mInjector.isPackageEphemeral(userId, packageName)) {
- return AppStandby.STANDBY_BUCKET_ACTIVE;
+ return STANDBY_BUCKET_ACTIVE;
}
return mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime);
@@ -811,7 +826,7 @@
}
void informListeners(String packageName, int userId, int bucket) {
- final boolean idle = bucket >= AppStandby.STANDBY_BUCKET_RARE;
+ final boolean idle = bucket >= STANDBY_BUCKET_RARE;
for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
listener.onAppIdleStateChanged(packageName, userId, idle, bucket);
}
@@ -878,6 +893,11 @@
String packageName = pi.packageName;
if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) {
mAppIdleHistory.reportUsage(packageName, userId, elapsedRealtime);
+ if (isAppSpecial(packageName, UserHandle.getAppId(pi.applicationInfo.uid),
+ userId)) {
+ mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
+ STANDBY_BUCKET_EXEMPTED, REASON_DEFAULT);
+ }
}
}
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index e55e073..9705469 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -503,7 +503,7 @@
mCal.getTimeInMillis());
mCal.setTimeInMillis(currentTimeMillis);
- mCal.addDays(-7);
+ mCal.addDays(-10);
pruneFilesOlderThan(mIntervalDirs[UsageStatsManager.INTERVAL_DAILY],
mCal.getTimeInMillis());
@@ -803,4 +803,4 @@
}
directory.delete();
}
-}
\ No newline at end of file
+}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 65c1cef..0572771 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -20,11 +20,11 @@
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.IUidObserver;
-import android.app.usage.AppStandby;
import android.app.usage.ConfigurationStats;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageEvents;
-import android.app.usage.AppStandby.StandbyBuckets;
+import android.app.usage.UsageStatsManager;
+import android.app.usage.UsageStatsManager.StandbyBuckets;
import android.app.usage.UsageEvents.Event;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManagerInternal;
@@ -149,6 +149,8 @@
publishLocalService(UsageStatsManagerInternal.class, new LocalService());
publishBinderService(Context.USAGE_STATS_SERVICE, new BinderService());
+ // Make sure we initialize the data, in case job scheduler needs it early.
+ getUserDataAndInitializeIfNeededLocked(UserHandle.USER_SYSTEM, mSystemTimeSnapshot);
}
@Override
@@ -678,18 +680,22 @@
@Override
public int getAppStandbyBucket(String packageName, String callingPackage, int userId) {
- if (!hasPermission(callingPackage)) {
- throw new SecurityException("Don't have permission to query app standby bucket");
- }
-
final int callingUid = Binder.getCallingUid();
try {
userId = ActivityManager.getService().handleIncomingUser(
- Binder.getCallingPid(), callingUid, userId, false, true,
+ Binder.getCallingPid(), callingUid, userId, false, false,
"getAppStandbyBucket", null);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
+ // If the calling app is asking about itself, continue, else check for permission.
+ if (mPackageManagerInternal.getPackageUid(packageName, PackageManager.MATCH_ANY_USER,
+ userId) != callingUid) {
+ if (!hasPermission(callingPackage)) {
+ throw new SecurityException(
+ "Don't have permission to query app standby bucket");
+ }
+ }
final boolean obfuscateInstantApps = shouldObfuscateInstantAppsForCaller(callingUid,
userId);
final long token = Binder.clearCallingIdentity();
@@ -707,6 +713,10 @@
getContext().enforceCallingPermission(Manifest.permission.CHANGE_APP_IDLE_STATE,
"No permission to change app standby state");
+ if (bucket < UsageStatsManager.STANDBY_BUCKET_ACTIVE
+ || bucket > UsageStatsManager.STANDBY_BUCKET_NEVER) {
+ throw new IllegalArgumentException("Cannot set the standby bucket to " + bucket);
+ }
final int callingUid = Binder.getCallingUid();
try {
userId = ActivityManager.getService().handleIncomingUser(
@@ -717,8 +727,13 @@
}
final long token = Binder.clearCallingIdentity();
try {
+ // Caller cannot set their own standby state
+ if (mPackageManagerInternal.getPackageUid(packageName,
+ PackageManager.MATCH_ANY_USER, userId) == callingUid) {
+ throw new IllegalArgumentException("Cannot set your own standby bucket");
+ }
mAppStandby.setAppStandbyBucket(packageName, userId, bucket,
- AppStandby.REASON_PREDICTED + ":" + callingUid,
+ UsageStatsManager.REASON_PREDICTED + ":" + callingUid,
SystemClock.elapsedRealtime());
} finally {
Binder.restoreCallingIdentity(token);
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index d359b70..7bea8a1 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -255,6 +255,7 @@
}
private void alsaFileAdded(String name) {
+ Slog.i(TAG, "alsaFileAdded(" + name + ")");
int type = AlsaDevice.TYPE_UNKNOWN;
int card = -1, device = -1;
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 9bc9cd0..e76d211 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -19,13 +19,8 @@
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
-import android.hardware.usb.UsbConfiguration;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbDeviceConnection;
-import android.hardware.usb.UsbEndpoint;
-import android.hardware.usb.UsbInterface;
-import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.text.TextUtils;
@@ -34,46 +29,113 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.usb.descriptors.UsbDescriptorParser;
+import com.android.server.usb.descriptors.UsbDeviceDescriptor;
import com.android.server.usb.descriptors.report.TextReportCanvas;
import com.android.server.usb.descriptors.tree.UsbDescriptorsTree;
-import java.util.ArrayList;
-import java.util.Collection;
+import java.text.SimpleDateFormat;
+import java.util.Date;
import java.util.HashMap;
+import java.util.LinkedList;
/**
* UsbHostManager manages USB state in host mode.
*/
public class UsbHostManager {
private static final String TAG = UsbHostManager.class.getSimpleName();
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true;
private final Context mContext;
- // contains all connected USB devices
- private final HashMap<String, UsbDevice> mDevices = new HashMap<>();
-
// USB busses to exclude from USB host support
private final String[] mHostBlacklist;
- private final Object mLock = new Object();
-
- private UsbDevice mNewDevice;
- private UsbConfiguration mNewConfiguration;
- private UsbInterface mNewInterface;
- private ArrayList<UsbConfiguration> mNewConfigurations;
- private ArrayList<UsbInterface> mNewInterfaces;
- private ArrayList<UsbEndpoint> mNewEndpoints;
-
private final UsbAlsaManager mUsbAlsaManager;
private final UsbSettingsManager mSettingsManager;
+ private final Object mLock = new Object();
@GuardedBy("mLock")
+ // contains all connected USB devices
+ private final HashMap<String, UsbDevice> mDevices = new HashMap<>();
+
+ private Object mSettingsLock = new Object();
+ @GuardedBy("mSettingsLock")
private UsbProfileGroupSettingsManager mCurrentSettings;
- @GuardedBy("mLock")
+ private Object mHandlerLock = new Object();
+ @GuardedBy("mHandlerLock")
private ComponentName mUsbDeviceConnectionHandler;
+ /*
+ * Member used for tracking connections & disconnections
+ */
+ static final SimpleDateFormat sFormat = new SimpleDateFormat("MM-dd HH:mm:ss:SSS");
+ private static final int MAX_CONNECT_RECORDS = 32;
+ private int mNumConnects; // TOTAL # of connect/disconnect
+ private final LinkedList<ConnectionRecord> mConnections = new LinkedList<ConnectionRecord>();
+ private ConnectionRecord mLastConnect;
+
+ /*
+ * ConnectionRecord
+ * Stores connection/disconnection data.
+ */
+ class ConnectionRecord {
+ long mTimestamp; // Same time-base as system log.
+ String mDeviceAddress;
+
+ static final int CONNECT = 0;
+ static final int DISCONNECT = 1;
+ final int mMode;
+ final byte[] mDescriptors;
+
+ ConnectionRecord(String deviceAddress, int mode, byte[] descriptors) {
+ mTimestamp = System.currentTimeMillis();
+ mDeviceAddress = deviceAddress;
+ mMode = mode;
+ mDescriptors = descriptors;
+ }
+
+ private String formatTime() {
+ return (new StringBuilder(sFormat.format(new Date(mTimestamp)))).toString();
+ }
+
+ void dumpShort(IndentingPrintWriter pw) {
+ if (mMode == CONNECT) {
+ pw.println(formatTime() + " Connect " + mDeviceAddress);
+ UsbDescriptorParser parser = new UsbDescriptorParser(mDeviceAddress, mDescriptors);
+
+ UsbDeviceDescriptor deviceDescriptor = parser.getDeviceDescriptor();
+
+ pw.println("manfacturer:0x" + Integer.toHexString(deviceDescriptor.getVendorID())
+ + " product:" + Integer.toHexString(deviceDescriptor.getProductID()));
+ pw.println("isHeadset[in: " + parser.isInputHeadset()
+ + " , out: " + parser.isOutputHeadset() + "]");
+ } else {
+ pw.println(formatTime() + " Disconnect " + mDeviceAddress);
+ }
+ }
+
+ void dumpLong(IndentingPrintWriter pw) {
+ if (mMode == CONNECT) {
+ pw.println(formatTime() + " Connect " + mDeviceAddress);
+ UsbDescriptorParser parser = new UsbDescriptorParser(mDeviceAddress, mDescriptors);
+ StringBuilder stringBuilder = new StringBuilder();
+ UsbDescriptorsTree descriptorTree = new UsbDescriptorsTree();
+ descriptorTree.parse(parser);
+ descriptorTree.report(new TextReportCanvas(parser, stringBuilder));
+
+ stringBuilder.append("isHeadset[in: " + parser.isInputHeadset()
+ + " , out: " + parser.isOutputHeadset() + "]");
+ pw.println(stringBuilder.toString());
+ } else {
+ pw.println(formatTime() + " Disconnect " + mDeviceAddress);
+ }
+ }
+ }
+
+ /*
+ * UsbHostManager
+ */
public UsbHostManager(Context context, UsbAlsaManager alsaManager,
UsbSettingsManager settingsManager) {
mContext = context;
@@ -91,33 +153,33 @@
}
public void setCurrentUserSettings(UsbProfileGroupSettingsManager settings) {
- synchronized (mLock) {
+ synchronized (mSettingsLock) {
mCurrentSettings = settings;
}
}
private UsbProfileGroupSettingsManager getCurrentUserSettings() {
- synchronized (mLock) {
+ synchronized (mSettingsLock) {
return mCurrentSettings;
}
}
public void setUsbDeviceConnectionHandler(@Nullable ComponentName usbDeviceConnectionHandler) {
- synchronized (mLock) {
+ synchronized (mHandlerLock) {
mUsbDeviceConnectionHandler = usbDeviceConnectionHandler;
}
}
private @Nullable ComponentName getUsbDeviceConnectionHandler() {
- synchronized (mLock) {
+ synchronized (mHandlerLock) {
return mUsbDeviceConnectionHandler;
}
}
- private boolean isBlackListed(String deviceName) {
+ private boolean isBlackListed(String deviceAddress) {
int count = mHostBlacklist.length;
for (int i = 0; i < count; i++) {
- if (deviceName.startsWith(mHostBlacklist[i])) {
+ if (deviceAddress.startsWith(mHostBlacklist[i])) {
return true;
}
}
@@ -135,171 +197,98 @@
}
+ private void addConnectionRecord(String deviceAddress, int mode, byte[] rawDescriptors) {
+ mNumConnects++;
+ while (mConnections.size() >= MAX_CONNECT_RECORDS) {
+ mConnections.removeFirst();
+ }
+ ConnectionRecord rec =
+ new ConnectionRecord(deviceAddress, mode, rawDescriptors);
+ mConnections.add(rec);
+ if (mode == ConnectionRecord.CONNECT) {
+ mLastConnect = rec;
+ }
+ }
+
/* Called from JNI in monitorUsbHostBus() to report new USB devices
- Returns true if successful, in which case the JNI code will continue adding configurations,
- interfaces and endpoints, and finally call endUsbDeviceAdded after all descriptors
- have been processed
+ Returns true if successful, i.e. the USB Audio device descriptors are
+ correctly parsed and the unique device is added to the audio device list.
*/
@SuppressWarnings("unused")
- private boolean beginUsbDeviceAdded(String deviceName, int vendorID, int productID,
- int deviceClass, int deviceSubclass, int deviceProtocol,
- String manufacturerName, String productName, int version, String serialNumber) {
-
+ private boolean usbDeviceAdded(String deviceAddress, int deviceClass, int deviceSubclass,
+ byte[] descriptors) {
if (DEBUG) {
- Slog.d(TAG, "usb:UsbHostManager.beginUsbDeviceAdded(" + deviceName + ")");
- // Audio Class Codes:
- // Audio: 0x01
- // Audio Subclass Codes:
- // undefined: 0x00
- // audio control: 0x01
- // audio streaming: 0x02
- // midi streaming: 0x03
-
- // some useful debugging info
- Slog.d(TAG, "usb: nm:" + deviceName + " vnd:" + vendorID + " prd:" + productID + " cls:"
- + deviceClass + " sub:" + deviceSubclass + " proto:" + deviceProtocol);
+ Slog.d(TAG, "usbDeviceAdded(" + deviceAddress + ") - start");
}
- // OK this is non-obvious, but true. One can't tell if the device being attached is even
- // potentially an audio device without parsing the interface descriptors, so punt on any
- // such test until endUsbDeviceAdded() when we have that info.
-
- if (isBlackListed(deviceName) ||
- isBlackListed(deviceClass, deviceSubclass)) {
+ // check class/subclass first as it is more likely to be blacklisted
+ if (isBlackListed(deviceClass, deviceSubclass) || isBlackListed(deviceAddress)) {
+ if (DEBUG) {
+ Slog.d(TAG, "device is black listed");
+ }
return false;
}
synchronized (mLock) {
- if (mDevices.get(deviceName) != null) {
- Slog.w(TAG, "device already on mDevices list: " + deviceName);
+ if (mDevices.get(deviceAddress) != null) {
+ Slog.w(TAG, "device already on mDevices list: " + deviceAddress);
+ //TODO If this is the same peripheral as is being connected, replace
+ // it with the new connection.
return false;
}
- if (mNewDevice != null) {
- Slog.e(TAG, "mNewDevice is not null in endUsbDeviceAdded");
- return false;
- }
+ UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress);
+ if (parser.parseDescriptors(descriptors)) {
- // Create version string in "%.%" format
- String versionString = Integer.toString(version >> 8) + "." + (version & 0xFF);
-
- mNewDevice = new UsbDevice(deviceName, vendorID, productID,
- deviceClass, deviceSubclass, deviceProtocol,
- manufacturerName, productName, versionString, serialNumber);
-
- mNewConfigurations = new ArrayList<>();
- mNewInterfaces = new ArrayList<>();
- mNewEndpoints = new ArrayList<>();
- }
-
- return true;
- }
-
- /* Called from JNI in monitorUsbHostBus() to report new USB configuration for the device
- currently being added. Returns true if successful, false in case of error.
- */
- @SuppressWarnings("unused")
- private void addUsbConfiguration(int id, String name, int attributes, int maxPower) {
- if (mNewConfiguration != null) {
- mNewConfiguration.setInterfaces(
- mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()]));
- mNewInterfaces.clear();
- }
-
- mNewConfiguration = new UsbConfiguration(id, name, attributes, maxPower);
- mNewConfigurations.add(mNewConfiguration);
- }
-
- /* Called from JNI in monitorUsbHostBus() to report new USB interface for the device
- currently being added. Returns true if successful, false in case of error.
- */
- @SuppressWarnings("unused")
- private void addUsbInterface(int id, String name, int altSetting,
- int Class, int subClass, int protocol) {
- if (mNewInterface != null) {
- mNewInterface.setEndpoints(
- mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()]));
- mNewEndpoints.clear();
- }
-
- mNewInterface = new UsbInterface(id, altSetting, name, Class, subClass, protocol);
- mNewInterfaces.add(mNewInterface);
- }
-
- /* Called from JNI in monitorUsbHostBus() to report new USB endpoint for the device
- currently being added. Returns true if successful, false in case of error.
- */
- @SuppressWarnings("unused")
- private void addUsbEndpoint(int address, int attributes, int maxPacketSize, int interval) {
- mNewEndpoints.add(new UsbEndpoint(address, attributes, maxPacketSize, interval));
- }
-
- /* Called from JNI in monitorUsbHostBus() to finish adding a new device */
- @SuppressWarnings("unused")
- private void endUsbDeviceAdded() {
- if (DEBUG) {
- Slog.d(TAG, "usb:UsbHostManager.endUsbDeviceAdded()");
- }
- if (mNewInterface != null) {
- mNewInterface.setEndpoints(
- mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()]));
- }
- if (mNewConfiguration != null) {
- mNewConfiguration.setInterfaces(
- mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()]));
- }
-
-
- synchronized (mLock) {
- if (mNewDevice != null) {
- mNewDevice.setConfigurations(
- mNewConfigurations.toArray(
- new UsbConfiguration[mNewConfigurations.size()]));
- mDevices.put(mNewDevice.getDeviceName(), mNewDevice);
- Slog.d(TAG, "Added device " + mNewDevice);
+ UsbDevice newDevice = parser.toAndroidUsbDevice();
+ mDevices.put(deviceAddress, newDevice);
// It is fine to call this only for the current user as all broadcasts are sent to
// all profiles of the user and the dialogs should only show once.
ComponentName usbDeviceConnectionHandler = getUsbDeviceConnectionHandler();
if (usbDeviceConnectionHandler == null) {
- getCurrentUserSettings().deviceAttached(mNewDevice);
+ getCurrentUserSettings().deviceAttached(newDevice);
} else {
- getCurrentUserSettings().deviceAttachedForFixedHandler(mNewDevice,
+ getCurrentUserSettings().deviceAttachedForFixedHandler(newDevice,
usbDeviceConnectionHandler);
}
- // deviceName is something like: "/dev/bus/usb/001/001"
- UsbDescriptorParser parser = new UsbDescriptorParser();
- boolean isInputHeadset = false;
- boolean isOutputHeadset = false;
- if (parser.parseDevice(mNewDevice.getDeviceName())) {
- isInputHeadset = parser.isInputHeadset();
- isOutputHeadset = parser.isOutputHeadset();
- Slog.i(TAG, "---- isHeadset[in: " + isInputHeadset
- + " , out: " + isOutputHeadset + "]");
- }
- mUsbAlsaManager.usbDeviceAdded(mNewDevice,
- isInputHeadset, isOutputHeadset);
+
+ // Headset?
+ boolean isInputHeadset = parser.isInputHeadset();
+ boolean isOutputHeadset = parser.isOutputHeadset();
+ Slog.i(TAG, "---- isHeadset[in: " + isInputHeadset
+ + " , out: " + isOutputHeadset + "]");
+
+ mUsbAlsaManager.usbDeviceAdded(newDevice, isInputHeadset, isOutputHeadset);
+
+ // Tracking
+ addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT,
+ parser.getRawDescriptors());
} else {
- Slog.e(TAG, "mNewDevice is null in endUsbDeviceAdded");
+ Slog.e(TAG, "Error parsing USB device descriptors for " + deviceAddress);
+ return false;
}
- mNewDevice = null;
- mNewConfigurations = null;
- mNewInterfaces = null;
- mNewEndpoints = null;
- mNewConfiguration = null;
- mNewInterface = null;
}
+
+ if (DEBUG) {
+ Slog.d(TAG, "beginUsbDeviceAdded(" + deviceAddress + ") end");
+ }
+
+ return true;
}
/* Called from JNI in monitorUsbHostBus to report USB device removal */
@SuppressWarnings("unused")
- private void usbDeviceRemoved(String deviceName) {
+ private void usbDeviceRemoved(String deviceAddress) {
synchronized (mLock) {
- UsbDevice device = mDevices.remove(deviceName);
+ UsbDevice device = mDevices.remove(deviceAddress);
if (device != null) {
mUsbAlsaManager.usbDeviceRemoved(device);
mSettingsManager.usbDeviceRemoved(device);
getCurrentUserSettings().usbDeviceRemoved(device);
+
+ // Tracking
+ addConnectionRecord(deviceAddress, ConnectionRecord.DISCONNECT, null);
}
}
}
@@ -323,58 +312,45 @@
}
/* Opens the specified USB device */
- public ParcelFileDescriptor openDevice(String deviceName, UsbUserSettingsManager settings,
+ public ParcelFileDescriptor openDevice(String deviceAddress, UsbUserSettingsManager settings,
String packageName, int uid) {
synchronized (mLock) {
- if (isBlackListed(deviceName)) {
+ if (isBlackListed(deviceAddress)) {
throw new SecurityException("USB device is on a restricted bus");
}
- UsbDevice device = mDevices.get(deviceName);
+ UsbDevice device = mDevices.get(deviceAddress);
if (device == null) {
// if it is not in mDevices, it either does not exist or is blacklisted
throw new IllegalArgumentException(
- "device " + deviceName + " does not exist or is restricted");
+ "device " + deviceAddress + " does not exist or is restricted");
}
+
settings.checkPermission(device, packageName, uid);
- return nativeOpenDevice(deviceName);
+ return nativeOpenDevice(deviceAddress);
}
}
public void dump(IndentingPrintWriter pw) {
- synchronized (mLock) {
- pw.println("USB Host State:");
- for (String name : mDevices.keySet()) {
- pw.println(" " + name + ": " + mDevices.get(name));
- }
+ pw.println("USB Host State:");
+ synchronized (mHandlerLock) {
if (mUsbDeviceConnectionHandler != null) {
pw.println("Default USB Host Connection handler: " + mUsbDeviceConnectionHandler);
}
+ }
+ synchronized (mLock) {
+ for (String name : mDevices.keySet()) {
+ pw.println(" " + name + ": " + mDevices.get(name));
+ }
- Collection<UsbDevice> devices = mDevices.values();
- if (devices.size() != 0) {
- pw.println("USB Peripheral Descriptors");
- for (UsbDevice device : devices) {
- StringBuilder stringBuilder = new StringBuilder();
+ pw.println("" + mNumConnects + " total connects/disconnects");
+ pw.println("Last " + mConnections.size() + " connections/disconnections");
+ for (ConnectionRecord rec : mConnections) {
+ rec.dumpShort(pw);
+ }
- UsbDescriptorParser parser = new UsbDescriptorParser();
- if (parser.parseDevice(device.getDeviceName())) {
- UsbDescriptorsTree descriptorTree = new UsbDescriptorsTree();
- descriptorTree.parse(parser);
-
- UsbManager usbManager =
- (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
- UsbDeviceConnection connection = usbManager.openDevice(device);
-
- descriptorTree.report(new TextReportCanvas(connection, stringBuilder));
- connection.close();
-
- stringBuilder.append("isHeadset[in: " + parser.isInputHeadset()
- + " , out: " + parser.isOutputHeadset() + "]");
- } else {
- stringBuilder.append("Error Parsing USB Descriptors");
- }
- pw.println(stringBuilder.toString());
- }
+ if (mLastConnect != null) {
+ pw.println("Last Connected USB Device:");
+ mLastConnect.dumpLong(pw);
}
}
@@ -382,5 +358,5 @@
}
private native void monitorUsbHostBus();
- private native ParcelFileDescriptor nativeOpenDevice(String deviceName);
+ private native ParcelFileDescriptor nativeOpenDevice(String deviceAddress);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb10ACHeader.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ACHeader.java
index a35b463..7763150 100644
--- a/services/usb/java/com/android/server/usb/descriptors/Usb10ACHeader.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ACHeader.java
@@ -32,7 +32,7 @@
// numbers associate with this endpoint
private byte mControls; // Vers 2.0 thing
- public Usb10ACHeader(int length, byte type, byte subtype, byte subclass, int spec) {
+ public Usb10ACHeader(int length, byte type, byte subtype, int subclass, int spec) {
super(length, type, subtype, subclass, spec);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb10ACInputTerminal.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ACInputTerminal.java
index 2363c4d..75531d1 100644
--- a/services/usb/java/com/android/server/usb/descriptors/Usb10ACInputTerminal.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ACInputTerminal.java
@@ -32,7 +32,7 @@
private byte mChannelNames; // 10:1 Unused (0x00)
private byte mTerminal; // 11:1 Unused (0x00)
- public Usb10ACInputTerminal(int length, byte type, byte subtype, byte subclass) {
+ public Usb10ACInputTerminal(int length, byte type, byte subtype, int subclass) {
super(length, type, subtype, subclass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb10ACMixerUnit.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ACMixerUnit.java
index d348664..c7634ba 100644
--- a/services/usb/java/com/android/server/usb/descriptors/Usb10ACMixerUnit.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ACMixerUnit.java
@@ -30,7 +30,7 @@
private byte[] mControls; // bitmasks of which controls are present for each channel
private byte mNameID; // string descriptor ID of mixer name
- public Usb10ACMixerUnit(int length, byte type, byte subtype, byte subClass) {
+ public Usb10ACMixerUnit(int length, byte type, byte subtype, int subClass) {
super(length, type, subtype, subClass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb10ACOutputTerminal.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ACOutputTerminal.java
index 9f2f09e..468ae57 100644
--- a/services/usb/java/com/android/server/usb/descriptors/Usb10ACOutputTerminal.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ACOutputTerminal.java
@@ -28,7 +28,7 @@
private byte mSourceID; // 7:1 From Input Terminal. (0x01)
private byte mTerminal; // 8:1 Unused.
- public Usb10ACOutputTerminal(int length, byte type, byte subtype, byte subClass) {
+ public Usb10ACOutputTerminal(int length, byte type, byte subtype, int subClass) {
super(length, type, subtype, subClass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatI.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatI.java
index 1523bb5..1d8498a 100644
--- a/services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatI.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatI.java
@@ -33,7 +33,7 @@
// min & max rates otherwise mSamFreqType rates.
// All 3-byte values. All rates in Hz
- public Usb10ASFormatI(int length, byte type, byte subtype, byte formatType, byte subclass) {
+ public Usb10ASFormatI(int length, byte type, byte subtype, byte formatType, int subclass) {
super(length, type, subtype, formatType, subclass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatII.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatII.java
index b1e7680..3c45790 100644
--- a/services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatII.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatII.java
@@ -38,7 +38,7 @@
// the min & max rates. otherwise mSamFreqType rates.
// All 3-byte values. All rates in Hz
- public Usb10ASFormatII(int length, byte type, byte subtype, byte formatType, byte subclass) {
+ public Usb10ASFormatII(int length, byte type, byte subtype, byte formatType, int subclass) {
super(length, type, subtype, formatType, subclass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb10ASGeneral.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ASGeneral.java
index 2d4f604..4fbbb21 100644
--- a/services/usb/java/com/android/server/usb/descriptors/Usb10ASGeneral.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ASGeneral.java
@@ -34,7 +34,7 @@
private int mFormatTag; // 5:2 The Audio Data Format that has to be used to communicate
// with this interface.
- public Usb10ASGeneral(int length, byte type, byte subtype, byte subclass) {
+ public Usb10ASGeneral(int length, byte type, byte subtype, int subclass) {
super(length, type, subtype, subclass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ACHeader.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ACHeader.java
index eefae3d..fe1b502 100644
--- a/services/usb/java/com/android/server/usb/descriptors/Usb20ACHeader.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ACHeader.java
@@ -29,7 +29,7 @@
// See audio20.pdf Appendix A.7, “Audio Function Category Codes.”
private byte mControls; // 8:1 See audio20.pdf Table 4-5.
- public Usb20ACHeader(int length, byte type, byte subtype, byte subclass, int spec) {
+ public Usb20ACHeader(int length, byte type, byte subtype, int subclass, int spec) {
super(length, type, subtype, subclass, spec);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ACInputTerminal.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ACInputTerminal.java
index 3e2ac39..ee1b32c 100644
--- a/services/usb/java/com/android/server/usb/descriptors/Usb20ACInputTerminal.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ACInputTerminal.java
@@ -39,7 +39,7 @@
private byte mTerminalName; // 16:1 - Index of a string descriptor, describing the
// Input Terminal.
- public Usb20ACInputTerminal(int length, byte type, byte subtype, byte subclass) {
+ public Usb20ACInputTerminal(int length, byte type, byte subtype, int subclass) {
super(length, type, subtype, subclass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ACMixerUnit.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ACMixerUnit.java
index 1b267a6..ab96585 100644
--- a/services/usb/java/com/android/server/usb/descriptors/Usb20ACMixerUnit.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ACMixerUnit.java
@@ -33,7 +33,7 @@
private byte mNameID; // 12+p+N:1 Index of a string descriptor, describing the
// Mixer Unit.
- public Usb20ACMixerUnit(int length, byte type, byte subtype, byte subClass) {
+ public Usb20ACMixerUnit(int length, byte type, byte subtype, int subClass) {
super(length, type, subtype, subClass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ACOutputTerminal.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ACOutputTerminal.java
index 67478aa..20a97af 100644
--- a/services/usb/java/com/android/server/usb/descriptors/Usb20ACOutputTerminal.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ACOutputTerminal.java
@@ -34,7 +34,7 @@
private int mControls; // 9:2 - see Audio20.pdf Table 4-10
private byte mTerminalID; // 11:1 - Index of a string descriptor, describing the
- public Usb20ACOutputTerminal(int length, byte type, byte subtype, byte subClass) {
+ public Usb20ACOutputTerminal(int length, byte type, byte subtype, int subClass) {
super(length, type, subtype, subClass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatI.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatI.java
index c031996..7310a3e 100644
--- a/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatI.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatI.java
@@ -31,7 +31,7 @@
private byte mBitResolution; // 5:1 The number of effectively used bits from
// the available bits in an audio subslot.
- public Usb20ASFormatI(int length, byte type, byte subtype, byte formatType, byte subclass) {
+ public Usb20ASFormatI(int length, byte type, byte subtype, byte formatType, int subclass) {
super(length, type, subtype, formatType, subclass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatII.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatII.java
index dc44ff0..fe88743 100644
--- a/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatII.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatII.java
@@ -34,7 +34,7 @@
/**
* TBD
*/
- public Usb20ASFormatII(int length, byte type, byte subtype, byte formatType, byte subclass) {
+ public Usb20ASFormatII(int length, byte type, byte subtype, byte formatType, int subclass) {
super(length, type, subtype, formatType, subclass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIII.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIII.java
index b44a216..b0ba02f 100644
--- a/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIII.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIII.java
@@ -31,7 +31,7 @@
private byte mBitResolution; // 5:1 The number of effectively used bits from
// the available bits in an audio subframe.
- public Usb20ASFormatIII(int length, byte type, byte subtype, byte formatType, byte subclass) {
+ public Usb20ASFormatIII(int length, byte type, byte subtype, byte formatType, int subclass) {
super(length, type, subtype, formatType, subclass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ASGeneral.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ASGeneral.java
index 18d48a0..de20738 100644
--- a/services/usb/java/com/android/server/usb/descriptors/Usb20ASGeneral.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ASGeneral.java
@@ -41,7 +41,7 @@
private byte mChannelNames; // 15:1 Index of a string descriptor, describing the
// name of the first physical channel.
- public Usb20ASGeneral(int length, byte type, byte subtype, byte subclass) {
+ public Usb20ASGeneral(int length, byte type, byte subtype, int subclass) {
super(length, type, subtype, subclass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACAudioControlEndpoint.java b/services/usb/java/com/android/server/usb/descriptors/UsbACAudioControlEndpoint.java
index 6e1ce07..409e605c 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACAudioControlEndpoint.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACAudioControlEndpoint.java
@@ -38,7 +38,7 @@
static final byte ATTRIBSMASK_SYNC = 0x0C;
static final byte ATTRIBMASK_TRANS = 0x03;
- public UsbACAudioControlEndpoint(int length, byte type, byte subclass) {
+ public UsbACAudioControlEndpoint(int length, byte type, int subclass) {
super(length, type, subclass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACAudioStreamEndpoint.java b/services/usb/java/com/android/server/usb/descriptors/UsbACAudioStreamEndpoint.java
index d351902..e63bb74 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACAudioStreamEndpoint.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACAudioStreamEndpoint.java
@@ -24,7 +24,7 @@
private static final String TAG = "UsbACAudioStreamEndpoint";
//TODO data fields...
- public UsbACAudioStreamEndpoint(int length, byte type, byte subclass) {
+ public UsbACAudioStreamEndpoint(int length, byte type, int subclass) {
super(length, type, subclass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACEndpoint.java b/services/usb/java/com/android/server/usb/descriptors/UsbACEndpoint.java
index 4a6839d..7ebccf3 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACEndpoint.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACEndpoint.java
@@ -25,16 +25,16 @@
abstract class UsbACEndpoint extends UsbDescriptor {
private static final String TAG = "UsbACEndpoint";
- protected final byte mSubclass; // from the mSubclass member of the "enclosing"
- // Interface Descriptor, not the stream.
- protected byte mSubtype; // 2:1 HEADER descriptor subtype
+ protected final int mSubclass; // from the mSubclass member of the "enclosing"
+ // Interface Descriptor, not the stream.
+ protected byte mSubtype; // 2:1 HEADER descriptor subtype
- UsbACEndpoint(int length, byte type, byte subclass) {
+ UsbACEndpoint(int length, byte type, int subclass) {
super(length, type);
mSubclass = subclass;
}
- public byte getSubclass() {
+ public int getSubclass() {
return mSubclass;
}
@@ -52,7 +52,7 @@
public static UsbDescriptor allocDescriptor(UsbDescriptorParser parser,
int length, byte type) {
UsbInterfaceDescriptor interfaceDesc = parser.getCurInterface();
- byte subClass = interfaceDesc.getUsbSubclass();
+ int subClass = interfaceDesc.getUsbSubclass();
switch (subClass) {
case AUDIO_AUDIOCONTROL:
return new UsbACAudioControlEndpoint(length, type, subClass);
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACFeatureUnit.java b/services/usb/java/com/android/server/usb/descriptors/UsbACFeatureUnit.java
index ab3903b..2c7ef79 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACFeatureUnit.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACFeatureUnit.java
@@ -46,7 +46,7 @@
// logical channel
private byte mUnitName; // ?:1 Index of a string descriptor, describing this Feature Unit.
- public UsbACFeatureUnit(int length, byte type, byte subtype, byte subClass) {
+ public UsbACFeatureUnit(int length, byte type, byte subtype, int subClass) {
super(length, type, subtype, subClass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACHeaderInterface.java b/services/usb/java/com/android/server/usb/descriptors/UsbACHeaderInterface.java
index 01a355e..88d026e 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACHeaderInterface.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACHeaderInterface.java
@@ -31,7 +31,7 @@
// of this descriptor header and all Unit and Terminal descriptors.
public UsbACHeaderInterface(
- int length, byte type, byte subtype, byte subclass, int adcRelease) {
+ int length, byte type, byte subtype, int subclass, int adcRelease) {
super(length, type, subtype, subclass);
mADCRelease = adcRelease;
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACInterface.java b/services/usb/java/com/android/server/usb/descriptors/UsbACInterface.java
index df6c53f..38c12a1 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACInterface.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACInterface.java
@@ -78,10 +78,10 @@
public static final int FORMAT_III_IEC1937_MPEG2_Layer1LS = 0x2005;
protected final byte mSubtype; // 2:1 HEADER descriptor subtype
- protected final byte mSubclass; // from the mSubclass member of the
+ protected final int mSubclass; // from the mSubclass member of the
// "enclosing" Interface Descriptor
- public UsbACInterface(int length, byte type, byte subtype, byte subclass) {
+ public UsbACInterface(int length, byte type, byte subtype, int subclass) {
super(length, type);
mSubtype = subtype;
mSubclass = subclass;
@@ -91,12 +91,12 @@
return mSubtype;
}
- public byte getSubclass() {
+ public int getSubclass() {
return mSubclass;
}
private static UsbDescriptor allocAudioControlDescriptor(UsbDescriptorParser parser,
- ByteStream stream, int length, byte type, byte subtype, byte subClass) {
+ ByteStream stream, int length, byte type, byte subtype, int subClass) {
switch (subtype) {
case ACI_HEADER:
{
@@ -157,7 +157,7 @@
}
private static UsbDescriptor allocAudioStreamingDescriptor(UsbDescriptorParser parser,
- ByteStream stream, int length, byte type, byte subtype, byte subClass) {
+ ByteStream stream, int length, byte type, byte subtype, int subClass) {
//int spec = parser.getUsbSpec();
int acInterfaceSpec = parser.getACInterfaceSpec();
switch (subtype) {
@@ -182,7 +182,7 @@
}
private static UsbDescriptor allocMidiStreamingDescriptor(int length, byte type,
- byte subtype, byte subClass) {
+ byte subtype, int subClass) {
switch (subtype) {
case MSI_HEADER:
return new UsbMSMidiHeader(length, type, subtype, subClass);
@@ -212,7 +212,7 @@
int length, byte type) {
byte subtype = stream.getByte();
UsbInterfaceDescriptor interfaceDesc = parser.getCurInterface();
- byte subClass = interfaceDesc.getUsbSubclass();
+ int subClass = interfaceDesc.getUsbSubclass();
switch (subClass) {
case AUDIO_AUDIOCONTROL:
return allocAudioControlDescriptor(
@@ -236,7 +236,7 @@
public void report(ReportCanvas canvas) {
super.report(canvas);
- byte subClass = getSubclass();
+ int subClass = getSubclass();
String subClassName = UsbStrings.getACInterfaceSubclassName(subClass);
byte subtype = getSubtype();
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACInterfaceUnparsed.java b/services/usb/java/com/android/server/usb/descriptors/UsbACInterfaceUnparsed.java
index 9e00a79..bd027ae 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACInterfaceUnparsed.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACInterfaceUnparsed.java
@@ -22,7 +22,7 @@
public final class UsbACInterfaceUnparsed extends UsbACInterface {
private static final String TAG = "UsbACInterfaceUnparsed";
- public UsbACInterfaceUnparsed(int length, byte type, byte subtype, byte subClass) {
+ public UsbACInterfaceUnparsed(int length, byte type, byte subtype, int subClass) {
super(length, type, subtype, subClass);
}
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACMidiEndpoint.java b/services/usb/java/com/android/server/usb/descriptors/UsbACMidiEndpoint.java
index 9c31457..42ee889 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACMidiEndpoint.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACMidiEndpoint.java
@@ -28,7 +28,7 @@
private byte mNumJacks;
private byte[] mJackIds;
- public UsbACMidiEndpoint(int length, byte type, byte subclass) {
+ public UsbACMidiEndpoint(int length, byte type, int subclass) {
super(length, type, subclass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACMixerUnit.java b/services/usb/java/com/android/server/usb/descriptors/UsbACMixerUnit.java
index 88faed9..606fa2b 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACMixerUnit.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACMixerUnit.java
@@ -24,7 +24,7 @@
// are connected.
protected byte mNumOutputs; // The number of output channels
- public UsbACMixerUnit(int length, byte type, byte subtype, byte subClass) {
+ public UsbACMixerUnit(int length, byte type, byte subtype, int subClass) {
super(length, type, subtype, subClass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACSelectorUnit.java b/services/usb/java/com/android/server/usb/descriptors/UsbACSelectorUnit.java
index b16bc57..4644fe1 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACSelectorUnit.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACSelectorUnit.java
@@ -32,7 +32,7 @@
// Input Pin of this Selector Unit is connected.
private byte mNameIndex; // Index of a string descriptor, describing the Selector Unit.
- public UsbACSelectorUnit(int length, byte type, byte subtype, byte subClass) {
+ public UsbACSelectorUnit(int length, byte type, byte subtype, int subClass) {
super(length, type, subtype, subClass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java b/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java
index 2836508..36139d6 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java
@@ -32,7 +32,7 @@
protected int mTerminalType; // 4:2 USB Streaming. (0x0101)
protected byte mAssocTerminal; // 6:1 Unused (0x00)
- public UsbACTerminal(int length, byte type, byte subtype, byte subclass) {
+ public UsbACTerminal(int length, byte type, byte subtype, int subclass) {
super(length, type, subtype, subclass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbASFormat.java b/services/usb/java/com/android/server/usb/descriptors/UsbASFormat.java
index 7a92f9e..5e515a1 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbASFormat.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbASFormat.java
@@ -40,7 +40,7 @@
public static final byte EXT_FORMAT_TYPE_II = (byte) 0x82;
public static final byte EXT_FORMAT_TYPE_III = (byte) 0x83;
- public UsbASFormat(int length, byte type, byte subtype, byte formatType, byte mSubclass) {
+ public UsbASFormat(int length, byte type, byte subtype, byte formatType, int mSubclass) {
super(length, type, subtype, mSubclass);
mFormatType = formatType;
}
@@ -66,8 +66,8 @@
* stream.
*/
public static UsbDescriptor allocDescriptor(UsbDescriptorParser parser,
- ByteStream stream, int length, byte type,
- byte subtype, byte subclass) {
+ ByteStream stream, int length, byte type,
+ byte subtype, int subclass) {
byte formatType = stream.getByte();
int acInterfaceSpec = parser.getACInterfaceSpec();
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
index 75279c6..993778f 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
@@ -15,8 +15,13 @@
*/
package com.android.server.usb.descriptors;
+import android.hardware.usb.UsbConfiguration;
+import android.hardware.usb.UsbInterface;
+
import com.android.server.usb.descriptors.report.ReportCanvas;
+import java.util.ArrayList;
+
/**
* @hide
* An USB Config Descriptor.
@@ -25,15 +30,18 @@
public final class UsbConfigDescriptor extends UsbDescriptor {
private static final String TAG = "UsbConfigDescriptor";
- private int mTotalLength; // 2:2 Total length in bytes of data returned
+ private int mTotalLength; // 2:2 Total length in bytes of data returned
private byte mNumInterfaces; // 4:1 Number of Interfaces
- private byte mConfigValue; // 5:1 Value to use as an argument to select this configuration
- private byte mConfigIndex; // 6:1 Index of String Descriptor describing this configuration
- private byte mAttribs; // 7:1 D7 Reserved, set to 1. (USB 1.0 Bus Powered)
- // D6 Self Powered
- // D5 Remote Wakeup
- // D4..0 Reserved, set to 0.
- private byte mMaxPower; // 8:1 Maximum Power Consumption in 2mA units
+ private int mConfigValue; // 5:1 Value to use as an argument to select this configuration
+ private byte mConfigIndex; // 6:1 Index of String Descriptor describing this configuration
+ private int mAttribs; // 7:1 D7 Reserved, set to 1. (USB 1.0 Bus Powered)
+ // D6 Self Powered
+ // D5 Remote Wakeup
+ // D4..0 Reserved, set to 0.
+ private int mMaxPower; // 8:1 Maximum Power Consumption in 2mA units
+
+ private ArrayList<UsbInterfaceDescriptor> mInterfaceDescriptors =
+ new ArrayList<UsbInterfaceDescriptor>();
UsbConfigDescriptor(int length, byte type) {
super(length, type);
@@ -48,7 +56,7 @@
return mNumInterfaces;
}
- public byte getConfigValue() {
+ public int getConfigValue() {
return mConfigValue;
}
@@ -56,22 +64,38 @@
return mConfigIndex;
}
- public byte getAttribs() {
+ public int getAttribs() {
return mAttribs;
}
- public byte getMaxPower() {
+ public int getMaxPower() {
return mMaxPower;
}
+ void addInterfaceDescriptor(UsbInterfaceDescriptor interfaceDesc) {
+ mInterfaceDescriptors.add(interfaceDesc);
+ }
+
+ UsbConfiguration toAndroid(UsbDescriptorParser parser) {
+ String name = parser.getDescriptorString(mConfigIndex);
+ UsbConfiguration config = new
+ UsbConfiguration(mConfigValue, name, mAttribs, mMaxPower);
+ UsbInterface[] interfaces = new UsbInterface[mInterfaceDescriptors.size()];
+ for (int index = 0; index < mInterfaceDescriptors.size(); index++) {
+ interfaces[index] = mInterfaceDescriptors.get(index).toAndroid(parser);
+ }
+ config.setInterfaces(interfaces);
+ return config;
+ }
+
@Override
public int parseRawDescriptors(ByteStream stream) {
mTotalLength = stream.unpackUsbShort();
mNumInterfaces = stream.getByte();
- mConfigValue = stream.getByte();
+ mConfigValue = stream.getUnsignedByte();
mConfigIndex = stream.getByte();
- mAttribs = stream.getByte();
- mMaxPower = stream.getByte();
+ mAttribs = stream.getUnsignedByte();
+ mMaxPower = stream.getUnsignedByte();
return mLength;
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptor.java
index 8c7565b..3fc5fe3 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptor.java
@@ -85,36 +85,36 @@
public static final byte DESCRIPTORTYPE_ENDPOINT_COMPANION = 0x30; // 48
// Class IDs
- public static final byte CLASSID_DEVICE = 0x00;
- public static final byte CLASSID_AUDIO = 0x01;
- public static final byte CLASSID_COM = 0x02;
- public static final byte CLASSID_HID = 0x03;
- // public static final byte CLASSID_??? = 0x04;
- public static final byte CLASSID_PHYSICAL = 0x05;
- public static final byte CLASSID_IMAGE = 0x06;
- public static final byte CLASSID_PRINTER = 0x07;
- public static final byte CLASSID_STORAGE = 0x08;
- public static final byte CLASSID_HUB = 0x09;
- public static final byte CLASSID_CDC_CONTROL = 0x0A;
- public static final byte CLASSID_SMART_CARD = 0x0B;
- //public static final byte CLASSID_??? = 0x0C;
- public static final byte CLASSID_SECURITY = 0x0D;
- public static final byte CLASSID_VIDEO = 0x0E;
- public static final byte CLASSID_HEALTHCARE = 0x0F;
- public static final byte CLASSID_AUDIOVIDEO = 0x10;
- public static final byte CLASSID_BILLBOARD = 0x11;
- public static final byte CLASSID_TYPECBRIDGE = 0x12;
- public static final byte CLASSID_DIAGNOSTIC = (byte) 0xDC;
- public static final byte CLASSID_WIRELESS = (byte) 0xE0;
- public static final byte CLASSID_MISC = (byte) 0xEF;
- public static final byte CLASSID_APPSPECIFIC = (byte) 0xFE;
- public static final byte CLASSID_VENDSPECIFIC = (byte) 0xFF;
+ public static final int CLASSID_DEVICE = 0x00;
+ public static final int CLASSID_AUDIO = 0x01;
+ public static final int CLASSID_COM = 0x02;
+ public static final int CLASSID_HID = 0x03;
+ // public static final int CLASSID_??? = 0x04;
+ public static final int CLASSID_PHYSICAL = 0x05;
+ public static final int CLASSID_IMAGE = 0x06;
+ public static final int CLASSID_PRINTER = 0x07;
+ public static final int CLASSID_STORAGE = 0x08;
+ public static final int CLASSID_HUB = 0x09;
+ public static final int CLASSID_CDC_CONTROL = 0x0A;
+ public static final int CLASSID_SMART_CARD = 0x0B;
+ //public static final int CLASSID_??? = 0x0C;
+ public static final int CLASSID_SECURITY = 0x0D;
+ public static final int CLASSID_VIDEO = 0x0E;
+ public static final int CLASSID_HEALTHCARE = 0x0F;
+ public static final int CLASSID_AUDIOVIDEO = 0x10;
+ public static final int CLASSID_BILLBOARD = 0x11;
+ public static final int CLASSID_TYPECBRIDGE = 0x12;
+ public static final int CLASSID_DIAGNOSTIC = 0xDC;
+ public static final int CLASSID_WIRELESS = 0xE0;
+ public static final int CLASSID_MISC = 0xEF;
+ public static final int CLASSID_APPSPECIFIC = 0xFE;
+ public static final int CLASSID_VENDSPECIFIC = 0xFF;
// Audio Subclass codes
- public static final byte AUDIO_SUBCLASS_UNDEFINED = 0x00;
- public static final byte AUDIO_AUDIOCONTROL = 0x01;
- public static final byte AUDIO_AUDIOSTREAMING = 0x02;
- public static final byte AUDIO_MIDISTREAMING = 0x03;
+ public static final int AUDIO_SUBCLASS_UNDEFINED = 0x00;
+ public static final int AUDIO_AUDIOCONTROL = 0x01;
+ public static final int AUDIO_AUDIOSTREAMING = 0x02;
+ public static final int AUDIO_MIDISTREAMING = 0x03;
// Request IDs
public static final int REQUEST_GET_STATUS = 0x00;
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
index ad7bde5c..78c7fdc 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -15,6 +15,7 @@
*/
package com.android.server.usb.descriptors;
+import android.hardware.usb.UsbDevice;
import android.util.Log;
import java.util.ArrayList;
@@ -25,11 +26,16 @@
*/
public final class UsbDescriptorParser {
private static final String TAG = "UsbDescriptorParser";
+ private static final boolean DEBUG = false;
+
+ private final String mDeviceAddr;
// Descriptor Objects
- private ArrayList<UsbDescriptor> mDescriptors = new ArrayList<UsbDescriptor>();
+ private static final int DESCRIPTORS_ALLOC_SIZE = 128;
+ private final ArrayList<UsbDescriptor> mDescriptors;
private UsbDeviceDescriptor mDeviceDescriptor;
+ private UsbConfigDescriptor mCurConfigDescriptor;
private UsbInterfaceDescriptor mCurInterfaceDescriptor;
// The AudioClass spec implemented by the AudioClass Interfaces
@@ -37,7 +43,35 @@
// Obtained from the first AudioClass Header descriptor.
private int mACInterfacesSpec = UsbDeviceDescriptor.USBSPEC_1_0;
- public UsbDescriptorParser() {}
+ public UsbDescriptorParser(String deviceAddr) {
+ mDeviceAddr = deviceAddr;
+ mDescriptors = new ArrayList<UsbDescriptor>(DESCRIPTORS_ALLOC_SIZE);
+ }
+
+ /**
+ * Connect this parser to an existing set of already parsed descriptors.
+ * This is useful for reporting.
+ */
+ public UsbDescriptorParser(String deviceAddr, ArrayList<UsbDescriptor> descriptors) {
+ mDeviceAddr = deviceAddr;
+ mDescriptors = descriptors;
+ //TODO some error checking here....
+ mDeviceDescriptor = (UsbDeviceDescriptor) descriptors.get(0);
+ }
+
+ /**
+ * Connect this parser to an byte array containing unparsed (raw) device descriptors
+ * to be parsed (and parse them). Useful for parsing a stored descriptor buffer.
+ */
+ public UsbDescriptorParser(String deviceAddr, byte[] rawDescriptors) {
+ mDeviceAddr = deviceAddr;
+ mDescriptors = new ArrayList<UsbDescriptor>(DESCRIPTORS_ALLOC_SIZE);
+ parseDescriptors(rawDescriptors);
+ }
+
+ public String getDeviceAddr() {
+ return mDeviceAddr;
+ }
/**
* @return the USB Spec value associated with the Device descriptor for the
@@ -60,6 +94,18 @@
public int getACInterfaceSpec() {
return mACInterfacesSpec;
}
+
+ private class UsbDescriptorsStreamFormatException extends Exception {
+ String mMessage;
+ UsbDescriptorsStreamFormatException(String message) {
+ mMessage = message;
+ }
+
+ public String toString() {
+ return "Descriptor Stream Format Exception: " + mMessage;
+ }
+ }
+
/**
* The probability (as returned by getHeadsetProbability() at which we conclude
* the peripheral is a headset.
@@ -67,7 +113,8 @@
private static final float IN_HEADSET_TRIGGER = 0.75f;
private static final float OUT_HEADSET_TRIGGER = 0.75f;
- private UsbDescriptor allocDescriptor(ByteStream stream) {
+ private UsbDescriptor allocDescriptor(ByteStream stream)
+ throws UsbDescriptorsStreamFormatException {
stream.resetReadCount();
int length = stream.getUnsignedByte();
@@ -83,15 +130,38 @@
break;
case UsbDescriptor.DESCRIPTORTYPE_CONFIG:
- descriptor = new UsbConfigDescriptor(length, type);
+ descriptor = mCurConfigDescriptor = new UsbConfigDescriptor(length, type);
+ if (mDeviceDescriptor != null) {
+ mDeviceDescriptor.addConfigDescriptor(mCurConfigDescriptor);
+ } else {
+ Log.e(TAG, "Config Descriptor found with no associated Device Descriptor!");
+ throw new UsbDescriptorsStreamFormatException(
+ "Config Descriptor found with no associated Device Descriptor!");
+ }
break;
case UsbDescriptor.DESCRIPTORTYPE_INTERFACE:
descriptor = mCurInterfaceDescriptor = new UsbInterfaceDescriptor(length, type);
+ if (mCurConfigDescriptor != null) {
+ mCurConfigDescriptor.addInterfaceDescriptor(mCurInterfaceDescriptor);
+ } else {
+ Log.e(TAG, "Interface Descriptor found with no associated Config Descriptor!");
+ throw new UsbDescriptorsStreamFormatException(
+ "Interface Descriptor found with no associated Config Descriptor!");
+ }
break;
case UsbDescriptor.DESCRIPTORTYPE_ENDPOINT:
descriptor = new UsbEndpointDescriptor(length, type);
+ if (mCurInterfaceDescriptor != null) {
+ mCurInterfaceDescriptor.addEndpointDescriptor(
+ (UsbEndpointDescriptor) descriptor);
+ } else {
+ Log.e(TAG,
+ "Endpoint Descriptor found with no associated Interface Descriptor!");
+ throw new UsbDescriptorsStreamFormatException(
+ "Endpoint Descriptor found with no associated Interface Descriptor!");
+ }
break;
/*
@@ -144,8 +214,10 @@
/**
* @hide
*/
- public void parseDescriptors(byte[] descriptors) {
- mDescriptors.clear();
+ public boolean parseDescriptors(byte[] descriptors) {
+ if (DEBUG) {
+ Log.d(TAG, "parseDescriptors() - start");
+ }
ByteStream stream = new ByteStream(descriptors);
while (stream.available() > 0) {
@@ -173,21 +245,36 @@
}
}
}
+ if (DEBUG) {
+ Log.d(TAG, "parseDescriptors() - end " + mDescriptors.size() + " descriptors.");
+ }
+ return true;
}
/**
* @hide
*/
- public boolean parseDevice(String deviceAddr) {
- byte[] rawDescriptors = getRawDescriptors(deviceAddr);
- if (rawDescriptors != null) {
- parseDescriptors(rawDescriptors);
- return true;
- }
- return false;
+ public boolean parseDevice() {
+ byte[] rawDescriptors = getRawDescriptors();
+
+ return rawDescriptors != null
+ ? parseDescriptors(rawDescriptors) : false;
}
- private native byte[] getRawDescriptors(String deviceAddr);
+ public byte[] getRawDescriptors() {
+ return getRawDescriptors_native(mDeviceAddr);
+ }
+
+ private native byte[] getRawDescriptors_native(String deviceAddr);
+
+ /**
+ * @hide
+ */
+ public String getDescriptorString(int stringId) {
+ return getDescriptorString_native(mDeviceAddr, stringId);
+ }
+
+ private native String getDescriptorString_native(String deviceAddr, int stringId);
public int getParsingSpec() {
return mDeviceDescriptor != null ? mDeviceDescriptor.getSpec() : 0;
@@ -200,6 +287,17 @@
/**
* @hide
*/
+ public UsbDevice toAndroidUsbDevice() {
+ if (mDeviceDescriptor == null) {
+ return null;
+ }
+
+ return mDeviceDescriptor.toAndroid(this);
+ }
+
+ /**
+ * @hide
+ */
public ArrayList<UsbDescriptor> getDescriptors(byte type) {
ArrayList<UsbDescriptor> list = new ArrayList<UsbDescriptor>();
for (UsbDescriptor descriptor : mDescriptors) {
@@ -213,7 +311,7 @@
/**
* @hide
*/
- public ArrayList<UsbDescriptor> getInterfaceDescriptorsForClass(byte usbClass) {
+ public ArrayList<UsbDescriptor> getInterfaceDescriptorsForClass(int usbClass) {
ArrayList<UsbDescriptor> list = new ArrayList<UsbDescriptor>();
for (UsbDescriptor descriptor : mDescriptors) {
// ensure that this isn't an unrecognized DESCRIPTORTYPE_INTERFACE
@@ -235,7 +333,7 @@
/**
* @hide
*/
- public ArrayList<UsbDescriptor> getACInterfaceDescriptors(byte subtype, byte subclass) {
+ public ArrayList<UsbDescriptor> getACInterfaceDescriptors(byte subtype, int subclass) {
ArrayList<UsbDescriptor> list = new ArrayList<UsbDescriptor>();
for (UsbDescriptor descriptor : mDescriptors) {
if (descriptor.getType() == UsbDescriptor.DESCRIPTORTYPE_AUDIO_INTERFACE) {
@@ -355,8 +453,6 @@
* to count on the peripheral being a headset.
*/
public boolean isInputHeadset() {
- // TEMP
- Log.i(TAG, "---- isInputHeadset() prob:" + (getInputHeadsetProbability() * 100f) + "%");
return getInputHeadsetProbability() >= IN_HEADSET_TRIGGER;
}
@@ -410,8 +506,6 @@
* to count on the peripheral being a headset.
*/
public boolean isOutputHeadset() {
- // TEMP
- Log.i(TAG, "---- isOutputHeadset() prob:" + (getOutputHeadsetProbability() * 100f) + "%");
return getOutputHeadsetProbability() >= OUT_HEADSET_TRIGGER;
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
index d5cb89e..8e7f0fd 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
@@ -15,9 +15,14 @@
*/
package com.android.server.usb.descriptors;
+import android.hardware.usb.UsbConfiguration;
+import android.hardware.usb.UsbDevice;
+
import com.android.server.usb.descriptors.report.ReportCanvas;
import com.android.server.usb.descriptors.report.UsbStrings;
+import java.util.ArrayList;
+
/**
* @hide
* A USB Device Descriptor.
@@ -31,9 +36,9 @@
public static final int USBSPEC_2_0 = 0x0200;
private int mSpec; // 2:2 bcdUSB 2 BCD USB Specification Number - BCD
- private byte mDevClass; // 4:1 class code
- private byte mDevSubClass; // 5:1 subclass code
- private byte mProtocol; // 6:1 protocol
+ private int mDevClass; // 4:1 class code
+ private int mDevSubClass; // 5:1 subclass code
+ private int mProtocol; // 6:1 protocol
private byte mPacketSize; // 7:1 Maximum Packet Size for Zero Endpoint.
// Valid Sizes are 8, 16, 32, 64
private int mVendorID; // 8:2 vendor ID
@@ -44,6 +49,9 @@
private byte mSerialNum; // 16:1 Index of Serial Number String Descriptor
private byte mNumConfigs; // 17:1 Number of Possible Configurations
+ private ArrayList<UsbConfigDescriptor> mConfigDescriptors =
+ new ArrayList<UsbConfigDescriptor>();
+
UsbDeviceDescriptor(int length, byte type) {
super(length, type);
mHierarchyLevel = 1;
@@ -53,15 +61,15 @@
return mSpec;
}
- public byte getDevClass() {
+ public int getDevClass() {
return mDevClass;
}
- public byte getDevSubClass() {
+ public int getDevSubClass() {
return mDevSubClass;
}
- public byte getProtocol() {
+ public int getProtocol() {
return mProtocol;
}
@@ -97,12 +105,41 @@
return mNumConfigs;
}
+ void addConfigDescriptor(UsbConfigDescriptor config) {
+ mConfigDescriptors.add(config);
+ }
+
+ /**
+ * @hide
+ */
+ public UsbDevice toAndroid(UsbDescriptorParser parser) {
+ String mfgName = parser.getDescriptorString(mMfgIndex);
+ String prodName = parser.getDescriptorString(mProductIndex);
+
+ // Create version string in "%.%" format
+ String versionString =
+ Integer.toString(mDeviceRelease >> 8) + "." + (mDeviceRelease & 0xFF);
+ String serialStr = parser.getDescriptorString(mSerialNum);
+
+ UsbDevice device = new UsbDevice(parser.getDeviceAddr(), mVendorID, mProductID,
+ mDevClass, mDevSubClass,
+ mProtocol, mfgName, prodName,
+ versionString, serialStr);
+ UsbConfiguration[] configs = new UsbConfiguration[mConfigDescriptors.size()];
+ for (int index = 0; index < mConfigDescriptors.size(); index++) {
+ configs[index] = mConfigDescriptors.get(index).toAndroid(parser);
+ }
+ device.setConfigurations(configs);
+
+ return device;
+ }
+
@Override
public int parseRawDescriptors(ByteStream stream) {
mSpec = stream.unpackUsbShort();
- mDevClass = stream.getByte();
- mDevSubClass = stream.getByte();
- mProtocol = stream.getByte();
+ mDevClass = stream.getUnsignedByte();
+ mDevSubClass = stream.getUnsignedByte();
+ mProtocol = stream.getUnsignedByte();
mPacketSize = stream.getByte();
mVendorID = stream.unpackUsbShort();
mProductID = stream.unpackUsbShort();
@@ -124,9 +161,9 @@
int spec = getSpec();
canvas.writeListItem("Spec: " + ReportCanvas.getBCDString(spec));
- byte devClass = getDevClass();
+ int devClass = getDevClass();
String classStr = UsbStrings.getClassName(devClass);
- byte devSubClass = getDevSubClass();
+ int devSubClass = getDevSubClass();
String subClasStr = UsbStrings.getClassName(devSubClass);
canvas.writeListItem("Class " + devClass + ": " + classStr + " Subclass"
+ devSubClass + ": " + subClasStr);
@@ -134,12 +171,11 @@
+ " Product ID: " + ReportCanvas.getHexString(getProductID())
+ " Product Release: " + ReportCanvas.getBCDString(getDeviceRelease()));
+ UsbDescriptorParser parser = canvas.getParser();
byte mfgIndex = getMfgIndex();
- String manufacturer =
- UsbDescriptor.getUsbDescriptorString(canvas.getConnection(), mfgIndex);
+ String manufacturer = parser.getDescriptorString(mfgIndex);
byte productIndex = getProductIndex();
- String product =
- UsbDescriptor.getUsbDescriptorString(canvas.getConnection(), productIndex);
+ String product = parser.getDescriptorString(productIndex);
canvas.writeListItem("Manufacturer " + mfgIndex + ": " + manufacturer
+ " Product " + productIndex + ": " + product);
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
index 6322fbe..1130238 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
@@ -15,6 +15,8 @@
*/
package com.android.server.usb.descriptors;
+import android.hardware.usb.UsbEndpoint;
+
import com.android.server.usb.descriptors.report.ReportCanvas;
/**
@@ -25,16 +27,16 @@
public class UsbEndpointDescriptor extends UsbDescriptor {
private static final String TAG = "UsbEndpointDescriptor";
- public static final byte MASK_ENDPOINT_ADDRESS = 0b0001111;
- public static final byte MASK_ENDPOINT_DIRECTION = (byte) 0b10000000;
- public static final byte DIRECTION_OUTPUT = 0x00;
- public static final byte DIRECTION_INPUT = (byte) 0x80;
+ public static final int MASK_ENDPOINT_ADDRESS = 0b000000000001111;
+ public static final int MASK_ENDPOINT_DIRECTION = (byte) 0b0000000010000000;
+ public static final int DIRECTION_OUTPUT = 0x0000;
+ public static final int DIRECTION_INPUT = (byte) 0x0080;
- public static final byte MASK_ATTRIBS_TRANSTYPE = 0b00000011;
- public static final byte TRANSTYPE_CONTROL = 0x00;
- public static final byte TRANSTYPE_ISO = 0x01;
- public static final byte TRANSTYPE_BULK = 0x02;
- public static final byte TRANSTYPE_INTERRUPT = 0x03;
+ public static final int MASK_ATTRIBS_TRANSTYPE = 0b00000011;
+ public static final int TRANSTYPE_CONTROL = 0x00;
+ public static final int TRANSTYPE_ISO = 0x01;
+ public static final int TRANSTYPE_BULK = 0x02;
+ public static final int TRANSTYPE_INTERRUPT = 0x03;
public static final byte MASK_ATTRIBS_SYNCTYPE = 0b00001100;
public static final byte SYNCTYPE_NONE = 0b00000000;
@@ -42,18 +44,18 @@
public static final byte SYNCTYPE_ADAPTSYNC = 0b00001000;
public static final byte SYNCTYPE_RESERVED = 0b00001100;
- public static final byte MASK_ATTRIBS_USEAGE = 0b00110000;
- public static final byte USEAGE_DATA = 0b00000000;
- public static final byte USEAGE_FEEDBACK = 0b00010000;
- public static final byte USEAGE_EXPLICIT = 0b00100000;
- public static final byte USEAGE_RESERVED = 0b00110000;
+ public static final int MASK_ATTRIBS_USEAGE = 0b00110000;
+ public static final int USEAGE_DATA = 0b00000000;
+ public static final int USEAGE_FEEDBACK = 0b00010000;
+ public static final int USEAGE_EXPLICIT = 0b00100000;
+ public static final int USEAGE_RESERVED = 0b00110000;
- private byte mEndpointAddress; // 2:1 Endpoint Address
+ private int mEndpointAddress; // 2:1 Endpoint Address
// Bits 0..3b Endpoint Number.
// Bits 4..6b Reserved. Set to Zero
// Bits 7 Direction 0 = Out, 1 = In
// (Ignored for Control Endpoints)
- private byte mAttributes; // 3:1 Various flags
+ private int mAttributes; // 3:1 Various flags
// Bits 0..1 Transfer Type:
// 00 = Control, 01 = Isochronous, 10 = Bulk, 11 = Interrupt
// Bits 2..7 are reserved. If Isochronous endpoint,
@@ -69,7 +71,7 @@
// 11: Reserved
private int mPacketSize; // 4:2 Maximum Packet Size this endpoint is capable of
// sending or receiving
- private byte mInterval; // 6:1 Interval for polling endpoint data transfers. Value in
+ private int mInterval; // 6:1 Interval for polling endpoint data transfers. Value in
// frame counts.
// Ignored for Bulk & Control Endpoints. Isochronous must equal
// 1 and field may range from 1 to 255 for interrupt endpoints.
@@ -81,11 +83,11 @@
mHierarchyLevel = 4;
}
- public byte getEndpointAddress() {
+ public int getEndpointAddress() {
return mEndpointAddress;
}
- public byte getAttributes() {
+ public int getAttributes() {
return mAttributes;
}
@@ -93,7 +95,7 @@
return mPacketSize;
}
- public byte getInterval() {
+ public int getInterval() {
return mInterval;
}
@@ -105,12 +107,16 @@
return mSyncAddress;
}
+ /* package */ UsbEndpoint toAndroid(UsbDescriptorParser parser) {
+ return new UsbEndpoint(mEndpointAddress, mAttributes, mPacketSize, mInterval);
+ }
+
@Override
public int parseRawDescriptors(ByteStream stream) {
- mEndpointAddress = stream.getByte();
- mAttributes = stream.getByte();
+ mEndpointAddress = stream.getUnsignedByte();
+ mAttributes = stream.getUnsignedByte();
mPacketSize = stream.unpackUsbShort();
- mInterval = stream.getByte();
+ mInterval = stream.getUnsignedByte();
if (mLength == 9) {
mRefresh = stream.getByte();
mSyncAddress = stream.getByte();
@@ -124,13 +130,13 @@
canvas.openList();
- byte address = getEndpointAddress();
+ int address = getEndpointAddress();
canvas.writeListItem("Address: "
+ ReportCanvas.getHexString(address & UsbEndpointDescriptor.MASK_ENDPOINT_ADDRESS)
+ ((address & UsbEndpointDescriptor.MASK_ENDPOINT_DIRECTION)
== UsbEndpointDescriptor.DIRECTION_OUTPUT ? " [out]" : " [in]"));
- byte attributes = getAttributes();
+ int attributes = getAttributes();
canvas.openListItem();
canvas.write("Attributes: " + ReportCanvas.getHexString(attributes) + " ");
switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_TRANSTYPE) {
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
index 4eef6ca..d87b1af 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
@@ -15,9 +15,14 @@
*/
package com.android.server.usb.descriptors;
+import android.hardware.usb.UsbEndpoint;
+import android.hardware.usb.UsbInterface;
+
import com.android.server.usb.descriptors.report.ReportCanvas;
import com.android.server.usb.descriptors.report.UsbStrings;
+import java.util.ArrayList;
+
/**
* @hide
* A common super-class for all USB Interface Descritor subtypes.
@@ -26,14 +31,17 @@
public class UsbInterfaceDescriptor extends UsbDescriptor {
private static final String TAG = "UsbInterfaceDescriptor";
- protected byte mInterfaceNumber; // 2:1 Number of Interface
+ protected int mInterfaceNumber; // 2:1 Number of Interface
protected byte mAlternateSetting; // 3:1 Value used to select alternative setting
protected byte mNumEndpoints; // 4:1 Number of Endpoints used for this interface
- protected byte mUsbClass; // 5:1 Class Code
- protected byte mUsbSubclass; // 6:1 Subclass Code
- protected byte mProtocol; // 7:1 Protocol Code
+ protected int mUsbClass; // 5:1 Class Code
+ protected int mUsbSubclass; // 6:1 Subclass Code
+ protected int mProtocol; // 7:1 Protocol Code
protected byte mDescrIndex; // 8:1 Index of String Descriptor Describing this interface
+ private ArrayList<UsbEndpointDescriptor> mEndpointDescriptors =
+ new ArrayList<UsbEndpointDescriptor>();
+
UsbInterfaceDescriptor(int length, byte type) {
super(length, type);
mHierarchyLevel = 3;
@@ -41,18 +49,18 @@
@Override
public int parseRawDescriptors(ByteStream stream) {
- mInterfaceNumber = stream.getByte();
+ mInterfaceNumber = stream.getUnsignedByte();
mAlternateSetting = stream.getByte();
mNumEndpoints = stream.getByte();
- mUsbClass = stream.getByte();
- mUsbSubclass = stream.getByte();
- mProtocol = stream.getByte();
+ mUsbClass = stream.getUnsignedByte();
+ mUsbSubclass = stream.getUnsignedByte();
+ mProtocol = stream.getUnsignedByte();
mDescrIndex = stream.getByte();
return mLength;
}
- public byte getInterfaceNumber() {
+ public int getInterfaceNumber() {
return mInterfaceNumber;
}
@@ -64,15 +72,15 @@
return mNumEndpoints;
}
- public byte getUsbClass() {
+ public int getUsbClass() {
return mUsbClass;
}
- public byte getUsbSubclass() {
+ public int getUsbSubclass() {
return mUsbSubclass;
}
- public byte getProtocol() {
+ public int getProtocol() {
return mProtocol;
}
@@ -80,13 +88,29 @@
return mDescrIndex;
}
+ void addEndpointDescriptor(UsbEndpointDescriptor endpoint) {
+ mEndpointDescriptors.add(endpoint);
+ }
+
+ UsbInterface toAndroid(UsbDescriptorParser parser) {
+ String name = parser.getDescriptorString(mDescrIndex);
+ UsbInterface ntrface = new UsbInterface(
+ mInterfaceNumber, mAlternateSetting, name, mUsbClass, mUsbSubclass, mProtocol);
+ UsbEndpoint[] endpoints = new UsbEndpoint[mEndpointDescriptors.size()];
+ for (int index = 0; index < mEndpointDescriptors.size(); index++) {
+ endpoints[index] = mEndpointDescriptors.get(index).toAndroid(parser);
+ }
+ ntrface.setEndpoints(endpoints);
+ return ntrface;
+ }
+
@Override
public void report(ReportCanvas canvas) {
super.report(canvas);
- byte usbClass = getUsbClass();
- byte usbSubclass = getUsbSubclass();
- byte protocol = getProtocol();
+ int usbClass = getUsbClass();
+ int usbSubclass = getUsbSubclass();
+ int protocol = getProtocol();
String className = UsbStrings.getClassName(usbClass);
String subclassName = "";
if (usbClass == UsbDescriptor.CLASSID_AUDIO) {
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiHeader.java b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiHeader.java
index 85a3e68..d0ca6db 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiHeader.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiHeader.java
@@ -25,7 +25,7 @@
public final class UsbMSMidiHeader extends UsbACInterface {
private static final String TAG = "UsbMSMidiHeader";
- public UsbMSMidiHeader(int length, byte type, byte subtype, byte subclass) {
+ public UsbMSMidiHeader(int length, byte type, byte subtype, int subclass) {
super(length, type, subtype, subclass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiInputJack.java b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiInputJack.java
index 1d5cbf2..7df7cfc 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiInputJack.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiInputJack.java
@@ -25,7 +25,7 @@
public final class UsbMSMidiInputJack extends UsbACInterface {
private static final String TAG = "UsbMSMidiInputJack";
- UsbMSMidiInputJack(int length, byte type, byte subtype, byte subclass) {
+ UsbMSMidiInputJack(int length, byte type, byte subtype, int subclass) {
super(length, type, subtype, subclass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiOutputJack.java b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiOutputJack.java
index 9f50240a..1879ac0 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiOutputJack.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiOutputJack.java
@@ -25,7 +25,7 @@
public final class UsbMSMidiOutputJack extends UsbACInterface {
private static final String TAG = "UsbMSMidiOutputJack";
- public UsbMSMidiOutputJack(int length, byte type, byte subtype, byte subclass) {
+ public UsbMSMidiOutputJack(int length, byte type, byte subtype, int subclass) {
super(length, type, subtype, subclass);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java b/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java
index 99ebcca..adfc514 100644
--- a/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java
+++ b/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java
@@ -15,7 +15,7 @@
*/
package com.android.server.usb.descriptors.report;
-import android.hardware.usb.UsbDeviceConnection;
+import com.android.server.usb.descriptors.UsbDescriptorParser;
/**
* @hide
@@ -32,8 +32,8 @@
* from the USB device.
* @param stringBuilder Generated output gets written into this object.
*/
- public HTMLReportCanvas(UsbDeviceConnection connection, StringBuilder stringBuilder) {
- super(connection);
+ public HTMLReportCanvas(UsbDescriptorParser parser, StringBuilder stringBuilder) {
+ super(parser);
mStringBuilder = stringBuilder;
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java b/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java
index 9e0adf5..c34dc98 100644
--- a/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java
+++ b/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java
@@ -15,7 +15,7 @@
*/
package com.android.server.usb.descriptors.report;
-import android.hardware.usb.UsbDeviceConnection;
+import com.android.server.usb.descriptors.UsbDescriptorParser;
/**
* @hide
@@ -24,22 +24,19 @@
public abstract class ReportCanvas {
private static final String TAG = "ReportCanvas";
- private final UsbDeviceConnection mConnection;
+ private final UsbDescriptorParser mParser;
/**
* Constructor.
* @param connection The USB connection object used to retrieve strings
* from the USB device.
*/
- public ReportCanvas(UsbDeviceConnection connection) {
- mConnection = connection;
+ public ReportCanvas(UsbDescriptorParser parser) {
+ mParser = parser;
}
- /**
- * @returns the UsbDeviceConnection member (mConnection).
- */
- public UsbDeviceConnection getConnection() {
- return mConnection;
+ public UsbDescriptorParser getParser() {
+ return mParser;
}
/**
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java b/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java
index a43569d..1e19ea1 100644
--- a/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java
+++ b/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java
@@ -15,7 +15,7 @@
*/
package com.android.server.usb.descriptors.report;
-import android.hardware.usb.UsbDeviceConnection;
+import com.android.server.usb.descriptors.UsbDescriptorParser;
/**
* @hide
@@ -34,8 +34,8 @@
* from the USB device.
* @param stringBuilder Generated output gets written into this object.
*/
- public TextReportCanvas(UsbDeviceConnection connection, StringBuilder stringBuilder) {
- super(connection);
+ public TextReportCanvas(UsbDescriptorParser parser, StringBuilder stringBuilder) {
+ super(parser);
mStringBuilder = stringBuilder;
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/UsbStrings.java b/services/usb/java/com/android/server/usb/descriptors/report/UsbStrings.java
index 64ecebc..fb4576a 100644
--- a/services/usb/java/com/android/server/usb/descriptors/report/UsbStrings.java
+++ b/services/usb/java/com/android/server/usb/descriptors/report/UsbStrings.java
@@ -32,8 +32,8 @@
private static HashMap<Byte, String> sDescriptorNames;
private static HashMap<Byte, String> sACControlInterfaceNames;
private static HashMap<Byte, String> sACStreamingInterfaceNames;
- private static HashMap<Byte, String> sClassNames;
- private static HashMap<Byte, String> sAudioSubclassNames;
+ private static HashMap<Integer, String> sClassNames;
+ private static HashMap<Integer, String> sAudioSubclassNames;
private static HashMap<Integer, String> sAudioEncodingNames;
private static HashMap<Integer, String> sTerminalNames;
private static HashMap<Integer, String> sFormatNames;
@@ -92,7 +92,7 @@
}
private static void initClassNames() {
- sClassNames = new HashMap<Byte, String>();
+ sClassNames = new HashMap<Integer, String>();
sClassNames.put(UsbDescriptor.CLASSID_DEVICE, "Device");
sClassNames.put(UsbDescriptor.CLASSID_AUDIO, "Audio");
sClassNames.put(UsbDescriptor.CLASSID_COM, "Communications");
@@ -118,7 +118,7 @@
}
private static void initAudioSubclassNames() {
- sAudioSubclassNames = new HashMap<Byte, String>();
+ sAudioSubclassNames = new HashMap<Integer, String>();
sAudioSubclassNames.put(UsbDescriptor.AUDIO_SUBCLASS_UNDEFINED, "Undefinded");
sAudioSubclassNames.put(UsbDescriptor.AUDIO_AUDIOCONTROL, "Audio Control");
sAudioSubclassNames.put(UsbDescriptor.AUDIO_AUDIOSTREAMING, "Audio Streaming");
@@ -300,7 +300,7 @@
/**
* Retrieves the name for the specified USB class ID.
*/
- public static String getClassName(byte classID) {
+ public static String getClassName(int classID) {
String name = sClassNames.get(classID);
int iClassID = classID & 0xFF;
return name != null
@@ -312,7 +312,7 @@
/**
* Retrieves the name for the specified USB audio subclass ID.
*/
- public static String getAudioSubclassName(byte subClassID) {
+ public static String getAudioSubclassName(int subClassID) {
String name = sAudioSubclassNames.get(subClassID);
int iSubclassID = subClassID & 0xFF;
return name != null
@@ -335,7 +335,7 @@
/**
* Retrieves the name for the specified USB audio interface subclass ID.
*/
- public static String getACInterfaceSubclassName(byte subClassID) {
+ public static String getACInterfaceSubclassName(int subClassID) {
return subClassID == UsbDescriptor.AUDIO_AUDIOCONTROL ? "AC Control" : "AC Streaming";
}
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 51c805d..cd3fdee 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -66,6 +66,7 @@
private SoundTriggerDbHelper mDbHelper;
private SoundTriggerHelper mSoundTriggerHelper;
private final TreeMap<UUID, SoundModel> mLoadedModels;
+ private Object mCallbacksLock;
private final TreeMap<UUID, LocalSoundTriggerRecognitionStatusCallback> mIntentCallbacks;
private PowerManager.WakeLock mWakelock;
@@ -75,6 +76,7 @@
mServiceStub = new SoundTriggerServiceStub();
mLocalSoundTriggerService = new LocalSoundTriggerService(context);
mLoadedModels = new TreeMap<UUID, SoundModel>();
+ mCallbacksLock = new Object();
mIntentCallbacks = new TreeMap<UUID, LocalSoundTriggerRecognitionStatusCallback>();
mLock = new Object();
}
@@ -211,7 +213,9 @@
// don't know if the other model is loaded.
if (oldModel != null && !oldModel.equals(soundModel)) {
mSoundTriggerHelper.unloadGenericSoundModel(soundModel.uuid);
- mIntentCallbacks.remove(soundModel.uuid);
+ synchronized (mCallbacksLock) {
+ mIntentCallbacks.remove(soundModel.uuid);
+ }
}
mLoadedModels.put(soundModel.uuid, soundModel);
}
@@ -240,7 +244,9 @@
// don't know if the other model is loaded.
if (oldModel != null && !oldModel.equals(soundModel)) {
mSoundTriggerHelper.unloadKeyphraseSoundModel(soundModel.keyphrases[0].id);
- mIntentCallbacks.remove(soundModel.uuid);
+ synchronized (mCallbacksLock) {
+ mIntentCallbacks.remove(soundModel.uuid);
+ }
}
mLoadedModels.put(soundModel.uuid, soundModel);
}
@@ -262,8 +268,10 @@
Slog.e(TAG, soundModelId + " is not loaded");
return STATUS_ERROR;
}
- LocalSoundTriggerRecognitionStatusCallback callback = mIntentCallbacks.get(
- soundModelId.getUuid());
+ LocalSoundTriggerRecognitionStatusCallback callback = null;
+ synchronized (mCallbacksLock) {
+ callback = mIntentCallbacks.get(soundModelId.getUuid());
+ }
if (callback != null) {
Slog.e(TAG, soundModelId + " is already running");
return STATUS_ERROR;
@@ -291,7 +299,9 @@
Slog.e(TAG, "Failed to start model: " + ret);
return ret;
}
- mIntentCallbacks.put(soundModelId.getUuid(), callback);
+ synchronized (mCallbacksLock) {
+ mIntentCallbacks.put(soundModelId.getUuid(), callback);
+ }
}
return STATUS_OK;
}
@@ -310,8 +320,10 @@
Slog.e(TAG, soundModelId + " is not loaded");
return STATUS_ERROR;
}
- LocalSoundTriggerRecognitionStatusCallback callback = mIntentCallbacks.get(
- soundModelId.getUuid());
+ LocalSoundTriggerRecognitionStatusCallback callback = null;
+ synchronized (mCallbacksLock) {
+ callback = mIntentCallbacks.get(soundModelId.getUuid());
+ }
if (callback == null) {
Slog.e(TAG, soundModelId + " is not running");
return STATUS_ERROR;
@@ -334,7 +346,9 @@
Slog.e(TAG, "Failed to stop model: " + ret);
return ret;
}
- mIntentCallbacks.remove(soundModelId.getUuid());
+ synchronized (mCallbacksLock) {
+ mIntentCallbacks.remove(soundModelId.getUuid());
+ }
}
return STATUS_OK;
}
@@ -379,14 +393,14 @@
public boolean isRecognitionActive(ParcelUuid parcelUuid) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
if (!isInitialized()) return false;
- synchronized (mLock) {
+ synchronized (mCallbacksLock) {
LocalSoundTriggerRecognitionStatusCallback callback =
mIntentCallbacks.get(parcelUuid.getUuid());
if (callback == null) {
return false;
}
- return mSoundTriggerHelper.isRecognitionRequested(parcelUuid.getUuid());
}
+ return mSoundTriggerHelper.isRecognitionRequested(parcelUuid.getUuid());
}
}
@@ -513,7 +527,7 @@
private void removeCallback(boolean releaseWakeLock) {
mCallbackIntent = null;
- synchronized (mLock) {
+ synchronized (mCallbacksLock) {
mIntentCallbacks.remove(mUuid);
if (releaseWakeLock) {
mWakelock.release();
@@ -523,7 +537,7 @@
}
private void grabWakeLock() {
- synchronized (mLock) {
+ synchronized (mCallbacksLock) {
if (mWakelock == null) {
PowerManager pm = ((PowerManager) mContext.getSystemService(Context.POWER_SERVICE));
mWakelock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
@@ -537,7 +551,7 @@
public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
String resultData, Bundle resultExtras) {
// We're only ever invoked when the callback is done, so release the lock.
- synchronized (mLock) {
+ synchronized (mCallbacksLock) {
mWakelock.release();
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 44e5314..2d93da9 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -427,8 +427,11 @@
if (hasComponent) {
mShortcutServiceInternal.setShortcutHostPackage(TAG,
serviceComponent.getPackageName(), mCurUser);
+ mAmInternal.setAllowAppSwitches(TAG,
+ serviceInfo.applicationInfo.uid, mCurUser);
} else {
mShortcutServiceInternal.setShortcutHostPackage(TAG, null, mCurUser);
+ mAmInternal.setAllowAppSwitches(TAG, -1, mCurUser);
}
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index a07f2bb..2091101 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -416,8 +416,15 @@
*/
public static final int PROPERTY_SELF_MANAGED = 0x00000100;
+ /**
+ * Indicates the call used Assisted Dialing.
+ * See also {@link Connection#PROPERTY_ASSISTED_DIALING_USED}
+ * @hide
+ */
+ public static final int PROPERTY_ASSISTED_DIALING_USED = 0x00000200;
+
//******************************************************************************************
- // Next PROPERTY value: 0x00000200
+ // Next PROPERTY value: 0x00000400
//******************************************************************************************
private final String mTelecomCallId;
@@ -577,6 +584,9 @@
if(hasProperty(properties, PROPERTY_HAS_CDMA_VOICE_PRIVACY)) {
builder.append(" PROPERTY_HAS_CDMA_VOICE_PRIVACY");
}
+ if(hasProperty(properties, PROPERTY_ASSISTED_DIALING_USED)) {
+ builder.append(" PROPERTY_ASSISTED_DIALING_USED");
+ }
builder.append("]");
return builder.toString();
}
@@ -858,7 +868,8 @@
* @hide
*/
@IntDef({HANDOVER_FAILURE_DEST_APP_REJECTED, HANDOVER_FAILURE_DEST_NOT_SUPPORTED,
- HANDOVER_FAILURE_DEST_INVALID_PERM, HANDOVER_FAILURE_DEST_USER_REJECTED})
+ HANDOVER_FAILURE_DEST_INVALID_PERM, HANDOVER_FAILURE_DEST_USER_REJECTED,
+ HANDOVER_FAILURE_ONGOING_EMERG_CALL})
@Retention(RetentionPolicy.SOURCE)
public @interface HandoverFailureErrors {}
@@ -886,6 +897,12 @@
*/
public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4;
+ /**
+ * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when there
+ * is ongoing emergency call.
+ */
+ public static final int HANDOVER_FAILURE_ONGOING_EMERG_CALL = 5;
+
/**
* Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
@@ -1935,6 +1952,15 @@
}
}
+ /** {@hide} */
+ final void internalOnHandoverFailed(int error) {
+ for (CallbackRecord<Callback> record : mCallbackRecords) {
+ final Call call = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(() -> callback.onHandoverFailed(call, error));
+ }
+ }
+
private void fireStateChanged(final int newState) {
for (CallbackRecord<Callback> record : mCallbackRecords) {
final Call call = this;
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 2bb1c4e..aaef8d3 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -23,7 +23,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.app.Notification;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
@@ -397,13 +396,17 @@
/**
* Set by the framework to indicate that a connection has an active RTT session associated with
* it.
- * @hide
*/
- @TestApi
public static final int PROPERTY_IS_RTT = 1 << 8;
+ /**
+ * Set by the framework to indicate that a connection is using assisted dialing.
+ * @hide
+ */
+ public static final int PROPERTY_ASSISTED_DIALING_USED = 1 << 9;
+
//**********************************************************************************************
- // Next PROPERTY value: 1<<9
+ // Next PROPERTY value: 1<<10
//**********************************************************************************************
/**
@@ -831,9 +834,7 @@
/**
* Provides methods to read and write RTT data to/from the in-call app.
- * @hide
*/
- @TestApi
public static final class RttTextStream {
private static final int READ_BUFFER_SIZE = 1000;
private final InputStreamReader mPipeFromInCall;
@@ -2608,10 +2609,8 @@
/**
* Informs listeners that a previously requested RTT session via
* {@link ConnectionRequest#isRequestingRtt()} or
- * {@link #onStartRtt(ParcelFileDescriptor, ParcelFileDescriptor)} has succeeded.
- * @hide
+ * {@link #onStartRtt(RttTextStream)} has succeeded.
*/
- @TestApi
public final void sendRttInitiationSuccess() {
setRttProperty();
mListeners.forEach((l) -> l.onRttInitiationSuccess(Connection.this));
@@ -2619,14 +2618,11 @@
/**
* Informs listeners that a previously requested RTT session via
- * {@link ConnectionRequest#isRequestingRtt()} or
- * {@link #onStartRtt(ParcelFileDescriptor, ParcelFileDescriptor)}
+ * {@link ConnectionRequest#isRequestingRtt()} or {@link #onStartRtt(RttTextStream)}
* has failed.
* @param reason One of the reason codes defined in {@link RttModifyStatus}, with the
* exception of {@link RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
- * @hide
*/
- @TestApi
public final void sendRttInitiationFailure(int reason) {
unsetRttProperty();
mListeners.forEach((l) -> l.onRttInitiationFailure(Connection.this, reason));
@@ -2635,9 +2631,7 @@
/**
* Informs listeners that a currently active RTT session has been terminated by the remote
* side of the coll.
- * @hide
*/
- @TestApi
public final void sendRttSessionRemotelyTerminated() {
mListeners.forEach((l) -> l.onRttSessionRemotelyTerminated(Connection.this));
}
@@ -2645,9 +2639,7 @@
/**
* Informs listeners that the remote side of the call has requested an upgrade to include an
* RTT session in the call.
- * @hide
*/
- @TestApi
public final void sendRemoteRttRequest() {
mListeners.forEach((l) -> l.onRemoteRttRequest(Connection.this));
}
@@ -2864,17 +2856,13 @@
* request, respectively.
* @param rttTextStream The object that should be used to send text to or receive text from
* the in-call app.
- * @hide
*/
- @TestApi
public void onStartRtt(@NonNull RttTextStream rttTextStream) {}
/**
* Notifies this {@link Connection} that it should terminate any existing RTT communication
* channel. No response to Telecom is needed for this method.
- * @hide
*/
- @TestApi
public void onStopRtt() {}
/**
@@ -2882,11 +2870,9 @@
* request sent via {@link #sendRemoteRttRequest}. Acceptance of the request is
* indicated by the supplied {@link RttTextStream} being non-null, and rejection is
* indicated by {@code rttTextStream} being {@code null}
- * @hide
* @param rttTextStream The object that should be used to send text to or receive text from
* the in-call app.
*/
- @TestApi
public void handleRttUpgradeResponse(@Nullable RttTextStream rttTextStream) {}
/**
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index e169e5f..658b473 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -16,7 +16,6 @@
package android.telecom;
-import android.annotation.TestApi;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
@@ -310,9 +309,7 @@
* send and receive RTT text to/from the in-call app.
* @return An instance of {@link android.telecom.Connection.RttTextStream}, or {@code null}
* if this connection request is not requesting an RTT session upon connection establishment.
- * @hide
*/
- @TestApi
public Connection.RttTextStream getRttTextStream() {
if (isRequestingRtt()) {
return new Connection.RttTextStream(mRttPipeToInCall, mRttPipeFromInCall);
@@ -324,9 +321,7 @@
/**
* Convenience method for determining whether the ConnectionRequest is requesting an RTT session
* @return {@code true} if RTT is requested, {@code false} otherwise.
- * @hide
*/
- @TestApi
public boolean isRequestingRtt() {
return mRttPipeFromInCall != null && mRttPipeToInCall != null;
}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 7e83306..7001615 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -143,6 +143,8 @@
private static final String SESSION_START_RTT = "CS.+RTT";
private static final String SESSION_STOP_RTT = "CS.-RTT";
private static final String SESSION_RTT_UPGRADE_RESPONSE = "CS.rTRUR";
+ private static final String SESSION_CONNECTION_SERVICE_FOCUS_LOST = "CS.cSFL";
+ private static final String SESSION_CONNECTION_SERVICE_FOCUS_GAINED = "CS.cSFG";
private static final int MSG_ADD_CONNECTION_SERVICE_ADAPTER = 1;
private static final int MSG_CREATE_CONNECTION = 2;
@@ -172,6 +174,8 @@
private static final int MSG_ON_STOP_RTT = 27;
private static final int MSG_RTT_UPGRADE_RESPONSE = 28;
private static final int MSG_CREATE_CONNECTION_COMPLETE = 29;
+ private static final int MSG_CONNECTION_SERVICE_FOCUS_LOST = 30;
+ private static final int MSG_CONNECTION_SERVICE_FOCUS_GAINED = 31;
private static Connection sNullConnection;
@@ -591,6 +595,26 @@
Log.endSession();
}
}
+
+ @Override
+ public void connectionServiceFocusLost(Session.Info sessionInfo) throws RemoteException {
+ Log.startSession(sessionInfo, SESSION_CONNECTION_SERVICE_FOCUS_LOST);
+ try {
+ mHandler.obtainMessage(MSG_CONNECTION_SERVICE_FOCUS_LOST).sendToTarget();
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
+ public void connectionServiceFocusGained(Session.Info sessionInfo) throws RemoteException {
+ Log.startSession(sessionInfo, SESSION_CONNECTION_SERVICE_FOCUS_GAINED);
+ try {
+ mHandler.obtainMessage(MSG_CONNECTION_SERVICE_FOCUS_GAINED).sendToTarget();
+ } finally {
+ Log.endSession();
+ }
+ }
};
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -1012,6 +1036,12 @@
}
break;
}
+ case MSG_CONNECTION_SERVICE_FOCUS_GAINED:
+ onConnectionServiceFocusGained();
+ break;
+ case MSG_CONNECTION_SERVICE_FOCUS_LOST:
+ onConnectionServiceFocusLost();
+ break;
default:
break;
}
@@ -1371,9 +1401,19 @@
isIncoming,
isUnknown);
- Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
- : isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
- : onCreateOutgoingConnection(callManagerAccount, request);
+ Connection connection = null;
+ if (request.getExtras() != null && request.getExtras().getBoolean(
+ TelecomManager.EXTRA_IS_HANDOVER,false)) {
+ if (!isIncoming) {
+ connection = onCreateOutgoingHandoverConnection(callManagerAccount, request);
+ } else {
+ // Todo: Call onCreateIncommingHandoverConnection()
+ }
+ } else {
+ connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
+ : isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
+ : onCreateOutgoingConnection(callManagerAccount, request);
+ }
Log.d(this, "createConnection, connection: %s", connection);
if (connection == null) {
connection = Connection.createFailedConnection(
@@ -1863,6 +1903,16 @@
}
/**
+ * Call to inform Telecom that your {@link ConnectionService} has released call resources (e.g
+ * microphone, camera).
+ *
+ * @see ConnectionService#onConnectionServiceFocusLost()
+ */
+ public final void connectionServiceFocusReleased() {
+ mAdapter.onConnectionServiceFocusReleased();
+ }
+
+ /**
* Adds a connection created by the {@link ConnectionService} and informs telecom of the new
* connection.
*
@@ -2136,6 +2186,20 @@
public void onRemoteExistingConnectionAdded(RemoteConnection connection) {}
/**
+ * Called when the {@link ConnectionService} has lost the call focus.
+ * The {@link ConnectionService} should release the call resources and invokes
+ * {@link ConnectionService#connectionServiceFocusReleased()} to inform telecom that it has
+ * released the call resources.
+ */
+ public void onConnectionServiceFocusLost() {}
+
+ /**
+ * Called when the {@link ConnectionService} has gained the call focus. The
+ * {@link ConnectionService} can acquire the call resources at this time.
+ */
+ public void onConnectionServiceFocusGained() {}
+
+ /**
* @hide
*/
public boolean containsConference(Conference conference) {
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index 92a9dc2..0d319bb 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -628,4 +628,17 @@
}
}
}
+
+ /**
+ * Notifies Telecom that the {@link ConnectionService} has released the call resource.
+ */
+ void onConnectionServiceFocusReleased() {
+ for (IConnectionServiceAdapter adapter : mAdapters) {
+ try {
+ Log.d(this, "onConnectionServiceFocusReleased");
+ adapter.onConnectionServiceFocusReleased(Log.getExternalSession());
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
}
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index 3fbdeb1..3e1bf77 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -73,6 +73,7 @@
private static final int MSG_ON_RTT_REMOTELY_TERMINATED = 32;
private static final int MSG_ON_RTT_UPGRADE_REQUEST = 33;
private static final int MSG_SET_PHONE_ACCOUNT_CHANGED = 34;
+ private static final int MSG_CONNECTION_SERVICE_FOCUS_RELEASED = 35;
private final IConnectionServiceAdapter mDelegate;
@@ -329,6 +330,9 @@
}
break;
}
+ case MSG_CONNECTION_SERVICE_FOCUS_RELEASED:
+ mDelegate.onConnectionServiceFocusReleased(null /*Session.Info*/);
+ break;
}
}
};
@@ -601,6 +605,11 @@
args.arg2 = pHandle;
mHandler.obtainMessage(MSG_SET_PHONE_ACCOUNT_CHANGED, args).sendToTarget();
}
+
+ @Override
+ public void onConnectionServiceFocusReleased(Session.Info sessionInfo) {
+ mHandler.obtainMessage(MSG_CONNECTION_SERVICE_FOCUS_RELEASED).sendToTarget();
+ }
};
public ConnectionServiceAdapterServant(IConnectionServiceAdapter delegate) {
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index d558bba..74fa62d 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -80,6 +80,7 @@
private static final int MSG_ON_CONNECTION_EVENT = 9;
private static final int MSG_ON_RTT_UPGRADE_REQUEST = 10;
private static final int MSG_ON_RTT_INITIATION_FAILURE = 11;
+ private static final int MSG_ON_HANDOVER_FAILED = 12;
/** Default Handler used to consolidate binder method calls onto a single thread. */
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -150,6 +151,12 @@
mPhone.internalOnRttInitiationFailure(callId, reason);
break;
}
+ case MSG_ON_HANDOVER_FAILED: {
+ String callId = (String) msg.obj;
+ int error = msg.arg1;
+ mPhone.internalOnHandoverFailed(callId, error);
+ break;
+ }
default:
break;
}
@@ -225,6 +232,11 @@
public void onRttInitiationFailure(String callId, int reason) {
mHandler.obtainMessage(MSG_ON_RTT_INITIATION_FAILURE, reason, 0, callId).sendToTarget();
}
+
+ @Override
+ public void onHandoverFailed(String callId, int error) {
+ mHandler.obtainMessage(MSG_ON_HANDOVER_FAILED, error, 0, callId).sendToTarget();
+ }
}
private Phone.Listener mPhoneListener = new Phone.Listener() {
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index 421b1a4..b5394b9 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -223,6 +223,13 @@
}
}
+ final void internalOnHandoverFailed(String callId, int error) {
+ Call call = mCallByTelecomCallId.get(callId);
+ if (call != null) {
+ call.internalOnHandoverFailed(error);
+ }
+ }
+
/**
* Called to destroy the phone and cleanup any lingering calls.
*/
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index 85906ad..59ce590 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -213,6 +213,9 @@
}
@Override
+ public void onConnectionServiceFocusReleased(Session.Info sessionInfo) {}
+
+ @Override
public void addConferenceCall(
final String callId, ParcelableConference parcel, Session.Info sessionInfo) {
RemoteConference conference = new RemoteConference(callId,
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 92d458f..15355ac 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -582,13 +582,29 @@
"android.telecom.extra.CALL_BACK_INTENT";
/**
+ * The dialer activity responsible for placing emergency calls from, for example, a locked
+ * keyguard.
+ * @hide
+ */
+ public static final ComponentName EMERGENCY_DIALER_COMPONENT =
+ ComponentName.createRelative("com.android.phone", ".EmergencyDialer");
+
+ /**
+ * The boolean indicated by this extra controls whether or not a call is eligible to undergo
+ * assisted dialing. This extra is stored under {@link #EXTRA_OUTGOING_CALL_EXTRAS}.
+ * @hide
+ */
+ public static final String EXTRA_USE_ASSISTED_DIALING =
+ "android.telecom.extra.USE_ASSISTED_DIALING";
+
+ /**
* The following 4 constants define how properties such as phone numbers and names are
* displayed to the user.
*/
/**
* Indicates that the address or number of a call is allowed to be displayed for caller ID.
- */
+ */
public static final int PRESENTATION_ALLOWED = 1;
/**
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index e428286..a740566 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -100,4 +100,8 @@
void respondToRttUpgradeRequest(String callId, in ParcelFileDescriptor fromInCall,
in ParcelFileDescriptor toInCall, in Session.Info sessionInfo);
+
+ void connectionServiceFocusLost(in Session.Info sessionInfo);
+
+ void connectionServiceFocusGained(in Session.Info sessionInfo);
}
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
index da2015f..be474bd 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -119,4 +119,6 @@
void onPhoneAccountChanged(String callId, in PhoneAccountHandle pHandle,
in Session.Info sessionInfo);
+
+ void onConnectionServiceFocusReleased(in Session.Info sessionInfo);
}
diff --git a/telecomm/java/com/android/internal/telecom/IInCallService.aidl b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
index e8cf8e9..110109e 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
@@ -54,4 +54,6 @@
void onRttUpgradeRequest(String callId, int id);
void onRttInitiationFailure(String callId, int reason);
+
+ void onHandoverFailed(String callId, int error);
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 1db6ef7..e9feb89 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -735,6 +735,14 @@
public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
/**
+ * Flag specifying whether signal strength is hidden in SIM Status screen,
+ * default to false.
+ * @hide
+ */
+ public static final String KEY_HIDE_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL =
+ "hide_signal_strength_in_sim_status_bool";
+
+ /**
* Flag specifying whether an additional (client initiated) intent needs to be sent on System
* update
*/
@@ -816,6 +824,14 @@
public static final String KEY_IMS_CONFERENCE_SIZE_LIMIT_INT = "ims_conference_size_limit_int";
/**
+ * Determines whether manage IMS conference calls is supported by a carrier. When {@code true},
+ * manage IMS conference call is supported, {@code false otherwise}.
+ * @hide
+ */
+ public static final String KEY_SUPPORT_MANAGE_IMS_CONFERENCE_CALL_BOOL =
+ "support_manage_ims_conference_call_bool";
+
+ /**
* Determines whether High Definition audio property is displayed in the dialer UI.
* If {@code false}, remove the HD audio property from the connection so that HD audio related
* UI is not displayed. If {@code true}, keep HD audio property as it is configured.
@@ -981,6 +997,12 @@
public static final String KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL =
"stk_disable_launch_browser_bool";
+ /**
+ * Boolean indicating if show data RAT icon on status bar even when data is disabled
+ * @hide
+ */
+ public static final String KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL =
+ "always_show_data_rat_icon_bool";
// These variables are used by the MMS service and exposed through another API, {@link
// SmsManager}. The variable names and string values are copied from there.
@@ -1760,6 +1782,7 @@
sDefaults.putString(KEY_CARRIER_VVM_PACKAGE_NAME_STRING, "");
sDefaults.putStringArray(KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL, false);
+ sDefaults.putBoolean(KEY_HIDE_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL, false);
sDefaults.putBoolean(KEY_CI_ACTION_ON_SYS_UPDATE_BOOL, false);
sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING, "");
sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING, "");
@@ -1814,6 +1837,7 @@
sDefaults.putInt(KEY_CDMA_3WAYCALL_FLASH_DELAY_INT , 0);
sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
sDefaults.putBoolean(KEY_SUPPORT_IMS_CONFERENCE_CALL_BOOL, true);
+ sDefaults.putBoolean(KEY_SUPPORT_MANAGE_IMS_CONFERENCE_CALL_BOOL, true);
sDefaults.putBoolean(KEY_SUPPORT_VIDEO_CONFERENCE_CALL_BOOL, false);
sDefaults.putBoolean(KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL, false);
sDefaults.putInt(KEY_IMS_CONFERENCE_SIZE_LIMIT_INT, 5);
@@ -1958,6 +1982,7 @@
sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_IDENTIFY_HIGH_DEFINITION_CALLS_IN_CALL_LOG_BOOL, false);
sDefaults.putBoolean(KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL, false);
+ sDefaults.putBoolean(KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL, false);
}
/**
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index c968406..376e6aa 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -202,7 +202,7 @@
* @return a 5 or 6 character string (MCC+MNC), null if any field is unknown
*/
public String getMobileNetworkOperator() {
- return (mMncStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
+ return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
}
/**
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 825dcc3..6ca5daf6 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -213,7 +213,7 @@
* @return a 5 or 6 character string (MCC+MNC), null if any field is unknown
*/
public String getMobileNetworkOperator() {
- return (mMncStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
+ return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
}
/**
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index e74b570..e4bb4f2 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -208,7 +208,7 @@
* @return a 5 or 6 character string (MCC+MNC), null if any field is unknown
*/
public String getMobileNetworkOperator() {
- return (mMncStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
+ return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
}
/**
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index c3a2ceb..56e1e64 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -280,6 +280,36 @@
* {@hide}
*/
public static final int NORMAL_UNSPECIFIED = 65;
+
+ /**
+ * Stk Call Control modified DIAL request to video DIAL request.
+ * {@hide}
+ */
+ public static final int DIAL_MODIFIED_TO_DIAL_VIDEO = 66;
+
+ /**
+ * Stk Call Control modified Video DIAL request to SS request.
+ * {@hide}
+ */
+ public static final int DIAL_VIDEO_MODIFIED_TO_SS = 67;
+
+ /**
+ * Stk Call Control modified Video DIAL request to USSD request.
+ * {@hide}
+ */
+ public static final int DIAL_VIDEO_MODIFIED_TO_USSD = 68;
+
+ /**
+ * Stk Call Control modified Video DIAL request to DIAL request.
+ * {@hide}
+ */
+ public static final int DIAL_VIDEO_MODIFIED_TO_DIAL = 69;
+
+ /**
+ * Stk Call Control modified Video DIAL request to Video DIAL request.
+ * {@hide}
+ */
+ public static final int DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO = 70;
//*********************************************************************************************
// When adding a disconnect type:
// 1) Update toString() with the newly added disconnect type.
@@ -382,6 +412,16 @@
return "DIAL_MODIFIED_TO_SS";
case DIAL_MODIFIED_TO_DIAL:
return "DIAL_MODIFIED_TO_DIAL";
+ case DIAL_MODIFIED_TO_DIAL_VIDEO:
+ return "DIAL_MODIFIED_TO_DIAL_VIDEO";
+ case DIAL_VIDEO_MODIFIED_TO_SS:
+ return "DIAL_VIDEO_MODIFIED_TO_SS";
+ case DIAL_VIDEO_MODIFIED_TO_USSD:
+ return "DIAL_VIDEO_MODIFIED_TO_USSD";
+ case DIAL_VIDEO_MODIFIED_TO_DIAL:
+ return "DIAL_VIDEO_MODIFIED_TO_DIAL";
+ case DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO:
+ return "DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO";
case ERROR_UNSPECIFIED:
return "ERROR_UNSPECIFIED";
case OUTGOING_FAILURE:
diff --git a/telephony/java/android/telephony/MbmsDownloadSession.java b/telephony/java/android/telephony/MbmsDownloadSession.java
index f392570..a554c69 100644
--- a/telephony/java/android/telephony/MbmsDownloadSession.java
+++ b/telephony/java/android/telephony/MbmsDownloadSession.java
@@ -347,6 +347,7 @@
@Override
public void onServiceDisconnected(ComponentName name) {
+ Log.w(LOG_TAG, "bindAndInitialize: Remote service disconnected");
sIsInitialized.set(false);
mService.set(null);
}
@@ -385,6 +386,7 @@
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService.set(null);
+ sIsInitialized.set(false);
sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
}
}
@@ -438,6 +440,7 @@
}
} catch (RemoteException e) {
mService.set(null);
+ sIsInitialized.set(false);
sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
return;
}
@@ -521,6 +524,7 @@
downloadService.download(request);
} catch (RemoteException e) {
mService.set(null);
+ sIsInitialized.set(false);
sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
}
}
@@ -542,6 +546,7 @@
return downloadService.listPendingDownloads(mSubscriptionId);
} catch (RemoteException e) {
mService.set(null);
+ sIsInitialized.set(false);
sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
return Collections.emptyList();
}
@@ -583,6 +588,7 @@
}
} catch (RemoteException e) {
mService.set(null);
+ sIsInitialized.set(false);
sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
return;
}
@@ -622,6 +628,7 @@
}
} catch (RemoteException e) {
mService.set(null);
+ sIsInitialized.set(false);
sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
}
} finally {
@@ -658,6 +665,7 @@
}
} catch (RemoteException e) {
mService.set(null);
+ sIsInitialized.set(false);
sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
return;
}
@@ -686,6 +694,7 @@
return downloadService.getDownloadStatus(downloadRequest, fileInfo);
} catch (RemoteException e) {
mService.set(null);
+ sIsInitialized.set(false);
sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
return STATUS_UNKNOWN;
}
@@ -727,6 +736,7 @@
}
} catch (RemoteException e) {
mService.set(null);
+ sIsInitialized.set(false);
sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
}
}
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 9ccfa94..c7e5131 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -408,7 +408,7 @@
/**
* Callback invoked when device call state changes.
* @param state call state
- * @param incomingNumber incoming call phone number. If application does not have
+ * @param phoneNumber call phone number. If application does not have
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} permission, an empty
* string will be passed as an argument.
*
@@ -416,7 +416,7 @@
* @see TelephonyManager#CALL_STATE_RINGING
* @see TelephonyManager#CALL_STATE_OFFHOOK
*/
- public void onCallStateChanged(int state, String incomingNumber) {
+ public void onCallStateChanged(int state, String phoneNumber) {
// default implementation empty
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 81806e5..99fc9b3 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -6641,6 +6641,7 @@
* @return PRLVersion or null if error.
* @hide
*/
+ @SystemApi
public String getCdmaPrlVersion() {
return getCdmaPrlVersion(getSubId());
}
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/telephony/java/android/telephony/data/DataCallResponse.aidl
similarity index 71%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to telephony/java/android/telephony/data/DataCallResponse.aidl
index 4ccdea5..e4cfd69 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/telephony/java/android/telephony/data/DataCallResponse.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 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.
@@ -14,11 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+/** @hide */
+package android.telephony.data;
-import android.telephony.SubscriptionInfo;
-
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
-}
-
+parcelable DataCallResponse;
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
new file mode 100644
index 0000000..8cdad3f
--- /dev/null
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2009 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ * Copyright (C) 2009 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.data;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Description of the response of a setup data call connection request.
+ *
+ * @hide
+ */
+@SystemApi
+public final class DataCallResponse implements Parcelable {
+ private final int mStatus;
+ private final int mSuggestedRetryTime;
+ private final int mCid;
+ private final int mActive;
+ private final String mType;
+ private final String mIfname;
+ private final List<InterfaceAddress> mAddresses;
+ private final List<InetAddress> mDnses;
+ private final List<InetAddress> mGateways;
+ private final List<String> mPcscfs;
+ private final int mMtu;
+
+ /**
+ * @param status Data call fail cause. 0 indicates no error.
+ * @param suggestedRetryTime The suggested data retry time in milliseconds.
+ * @param cid The unique id of the data connection.
+ * @param active Data connection active status. 0 = inactive, 1 = active/physical link down,
+ * 2 = active/physical link up.
+ * @param type The connection protocol, should be one of the PDP_type values in TS 27.007
+ * section 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP".
+ * @param ifname The network interface name.
+ * @param addresses A list of addresses with optional "/" prefix length, e.g.,
+ * "192.0.1.3" or "192.0.1.11/16 2001:db8::1/64". Typically 1 IPv4 or 1 IPv6 or
+ * one of each. If the prefix length is absent the addresses are assumed to be
+ * point to point with IPv4 having a prefix length of 32 and IPv6 128.
+ * @param dnses A list of DNS server addresses, e.g., "192.0.1.3" or
+ * "192.0.1.11 2001:db8::1". Null if no dns server addresses returned.
+ * @param gateways A list of default gateway addresses, e.g., "192.0.1.3" or
+ * "192.0.1.11 2001:db8::1". When null, the addresses represent point to point
+ * connections.
+ * @param pcscfs A list of Proxy Call State Control Function address via PCO(Protocol
+ * Configuration Option) for IMS client.
+ * @param mtu MTU (Maximum transmission unit) received from network Value <= 0 means network has
+ * either not sent a value or sent an invalid value.
+ */
+ public DataCallResponse(int status, int suggestedRetryTime, int cid, int active,
+ @Nullable String type, @Nullable String ifname,
+ @Nullable List<InterfaceAddress> addresses,
+ @Nullable List<InetAddress> dnses,
+ @Nullable List<InetAddress> gateways,
+ @Nullable List<String> pcscfs, int mtu) {
+ mStatus = status;
+ mSuggestedRetryTime = suggestedRetryTime;
+ mCid = cid;
+ mActive = active;
+ mType = (type == null) ? "" : type;
+ mIfname = (ifname == null) ? "" : ifname;
+ mAddresses = (addresses == null) ? new ArrayList<>() : addresses;
+ mDnses = (dnses == null) ? new ArrayList<>() : dnses;
+ mGateways = (gateways == null) ? new ArrayList<>() : gateways;
+ mPcscfs = (pcscfs == null) ? new ArrayList<>() : pcscfs;
+ mMtu = mtu;
+ }
+
+ public DataCallResponse(Parcel source) {
+ mStatus = source.readInt();
+ mSuggestedRetryTime = source.readInt();
+ mCid = source.readInt();
+ mActive = source.readInt();
+ mType = source.readString();
+ mIfname = source.readString();
+ mAddresses = new ArrayList<>();
+ source.readList(mAddresses, InterfaceAddress.class.getClassLoader());
+ mDnses = new ArrayList<>();
+ source.readList(mDnses, InetAddress.class.getClassLoader());
+ mGateways = new ArrayList<>();
+ source.readList(mGateways, InetAddress.class.getClassLoader());
+ mPcscfs = new ArrayList<>();
+ source.readList(mPcscfs, InetAddress.class.getClassLoader());
+ mMtu = source.readInt();
+ }
+
+ /**
+ * @return Data call fail cause. 0 indicates no error.
+ */
+ public int getStatus() { return mStatus; }
+
+ /**
+ * @return The suggested data retry time in milliseconds.
+ */
+ public int getSuggestedRetryTime() { return mSuggestedRetryTime; }
+
+
+ /**
+ * @return The unique id of the data connection.
+ */
+ public int getCallId() { return mCid; }
+
+ /**
+ * @return 0 = inactive, 1 = active/physical link down, 2 = active/physical link up.
+ */
+ public int getActive() { return mActive; }
+
+ /**
+ * @return The connection protocol, should be one of the PDP_type values in TS 27.007 section
+ * 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP".
+ */
+ @NonNull
+ public String getType() { return mType; }
+
+ /**
+ * @return The network interface name.
+ */
+ @NonNull
+ public String getIfname() { return mIfname; }
+
+ /**
+ * @return A list of {@link InterfaceAddress}
+ */
+ @NonNull
+ public List<InterfaceAddress> getAddresses() { return mAddresses; }
+
+ /**
+ * @return A list of DNS server addresses, e.g., "192.0.1.3" or
+ * "192.0.1.11 2001:db8::1". Empty list if no dns server addresses returned.
+ */
+ @NonNull
+ public List<InetAddress> getDnses() { return mDnses; }
+
+ /**
+ * @return A list of default gateway addresses, e.g., "192.0.1.3" or
+ * "192.0.1.11 2001:db8::1". Empty list if the addresses represent point to point connections.
+ */
+ @NonNull
+ public List<InetAddress> getGateways() { return mGateways; }
+
+ /**
+ * @return A list of Proxy Call State Control Function address via PCO(Protocol Configuration
+ * Option) for IMS client.
+ */
+ @NonNull
+ public List<String> getPcscfs() { return mPcscfs; }
+
+ /**
+ * @return MTU received from network Value <= 0 means network has either not sent a value or
+ * sent an invalid value
+ */
+ public int getMtu() { return mMtu; }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("DataCallResponse: {")
+ .append(" status=").append(mStatus)
+ .append(" retry=").append(mSuggestedRetryTime)
+ .append(" cid=").append(mCid)
+ .append(" active=").append(mActive)
+ .append(" type=").append(mType)
+ .append(" ifname=").append(mIfname)
+ .append(" mtu=").append(mMtu)
+ .append(" addresses=").append(mAddresses)
+ .append(" dnses=").append(mDnses)
+ .append(" gateways=").append(mGateways)
+ .append(" pcscf=").append(mPcscfs)
+ .append("}");
+ return sb.toString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mStatus);
+ dest.writeInt(mSuggestedRetryTime);
+ dest.writeInt(mCid);
+ dest.writeInt(mActive);
+ dest.writeString(mType);
+ dest.writeString(mIfname);
+ dest.writeList(mAddresses);
+ dest.writeList(mDnses);
+ dest.writeList(mGateways);
+ dest.writeList(mPcscfs);
+ dest.writeInt(mMtu);
+ }
+
+ public static final Parcelable.Creator<DataCallResponse> CREATOR =
+ new Parcelable.Creator<DataCallResponse>() {
+ @Override
+ public DataCallResponse createFromParcel(Parcel source) {
+ return new DataCallResponse(source);
+ }
+
+ @Override
+ public DataCallResponse[] newArray(int size) {
+ return new DataCallResponse[size];
+ }
+ };
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/telephony/java/android/telephony/data/InterfaceAddress.aidl
similarity index 71%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to telephony/java/android/telephony/data/InterfaceAddress.aidl
index 4ccdea5..d750363 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/telephony/java/android/telephony/data/InterfaceAddress.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 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.
@@ -14,11 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+/** @hide */
+package android.telephony.data;
-import android.telephony.SubscriptionInfo;
-
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
-}
-
+parcelable InterfaceAddress;
diff --git a/telephony/java/android/telephony/data/InterfaceAddress.java b/telephony/java/android/telephony/data/InterfaceAddress.java
new file mode 100644
index 0000000..947d0ff
--- /dev/null
+++ b/telephony/java/android/telephony/data/InterfaceAddress.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 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 android.telephony.data;
+
+import android.annotation.SystemApi;
+import android.net.NetworkUtils;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * This class represents a Network Interface address. In short it's an IP address, a subnet mask
+ * when the address is an IPv4 one. An IP address and a network prefix length in the case of IPv6
+ * address.
+ *
+ * @hide
+ */
+@SystemApi
+public final class InterfaceAddress implements Parcelable {
+
+ private final InetAddress mInetAddress;
+
+ private final int mPrefixLength;
+
+ /**
+ * @param inetAddress A {@link InetAddress} of the address
+ * @param prefixLength The network prefix length for this address.
+ */
+ public InterfaceAddress(InetAddress inetAddress, int prefixLength) {
+ mInetAddress = inetAddress;
+ mPrefixLength = prefixLength;
+ }
+
+ /**
+ * @param address The address in string format
+ * @param prefixLength The network prefix length for this address.
+ * @throws UnknownHostException
+ */
+ public InterfaceAddress(String address, int prefixLength) throws UnknownHostException {
+ InetAddress ia;
+ try {
+ ia = NetworkUtils.numericToInetAddress(address);
+ } catch (IllegalArgumentException e) {
+ throw new UnknownHostException("Non-numeric ip addr=" + address);
+ }
+ mInetAddress = ia;
+ mPrefixLength = prefixLength;
+ }
+
+ public InterfaceAddress(Parcel source) {
+ mInetAddress = (InetAddress) source.readSerializable();
+ mPrefixLength = source.readInt();
+ }
+
+ /**
+ * @return an InetAddress for this address.
+ */
+ public InetAddress getAddress() { return mInetAddress; }
+
+ /**
+ * @return The network prefix length for this address.
+ */
+ public int getNetworkPrefixLength() { return mPrefixLength; }
+
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return mInetAddress + "/" + mPrefixLength;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeSerializable(mInetAddress);
+ dest.writeInt(mPrefixLength);
+ }
+
+ public static final Parcelable.Creator<InterfaceAddress> CREATOR =
+ new Parcelable.Creator<InterfaceAddress>() {
+ @Override
+ public InterfaceAddress createFromParcel(Parcel source) {
+ return new InterfaceAddress(source);
+ }
+
+ @Override
+ public InterfaceAddress[] newArray(int size) {
+ return new InterfaceAddress[size];
+ }
+ };
+}
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index a13af5f..2507cfee 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -63,7 +63,7 @@
* embedded SIM.
*
* <p>The activity will immediately finish with {@link android.app.Activity#RESULT_CANCELED} if
- * {@link #isEnabled} is false or if the device is already provisioned.
+ * {@link #isEnabled} is false.
*
* TODO(b/35851809): Make this a SystemApi.
*/
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 062858d..ca4a210 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -188,6 +188,11 @@
}
/**
+ * Called when the feature is ready to use.
+ */
+ public abstract void onFeatureReady();
+
+ /**
* Called when the feature is being removed and must be cleaned up.
*/
public abstract void onFeatureRemoved();
diff --git a/telephony/java/android/telephony/ims/feature/MMTelFeature.java b/telephony/java/android/telephony/ims/feature/MMTelFeature.java
index e790d14..4e095e3a 100644
--- a/telephony/java/android/telephony/ims/feature/MMTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MMTelFeature.java
@@ -346,6 +346,11 @@
return null;
}
+ @Override
+ public void onFeatureReady() {
+
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index a82e608..40c5181 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -36,6 +36,11 @@
}
@Override
+ public void onFeatureReady() {
+
+ }
+
+ @Override
public void onFeatureRemoved() {
}
diff --git a/telephony/java/android/telephony/ims/feature/SmsFeature.java b/telephony/java/android/telephony/ims/feature/SmsFeature.java
new file mode 100644
index 0000000..c1366db
--- /dev/null
+++ b/telephony/java/android/telephony/ims/feature/SmsFeature.java
@@ -0,0 +1,237 @@
+/*
+ * 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 android.telephony.ims.feature;
+
+import android.annotation.SystemApi;
+import android.os.RemoteException;
+import com.android.ims.internal.IImsSmsFeature;
+import com.android.ims.internal.ISmsListener;
+
+/**
+ * Base implementation of SMS over IMS functionality.
+ *
+ * @hide
+ */
+public class SmsFeature extends ImsFeature {
+ /**
+ * SMS over IMS format is 3gpp.
+ */
+ public static final int IMS_SMS_FORMAT_3GPP = 1;
+
+ /**
+ * SMS over IMS format is 3gpp2.
+ */
+ public static final int IMS_SMS_FORMAT_3GPP2 = 2;
+
+ /**
+ * Message was sent successfully.
+ */
+ public static final int SEND_STATUS_OK = 1;
+
+ /**
+ * IMS provider failed to send the message and platform should not retry falling back to sending
+ * the message using the radio.
+ */
+ public static final int SEND_STATUS_ERROR = 2;
+
+ /**
+ * IMS provider failed to send the message and platform should retry again after setting TP-RD bit
+ * to high.
+ */
+ public static final int SEND_STATUS_ERROR_RETRY = 3;
+
+ /**
+ * IMS provider failed to send the message and platform should retry falling back to sending
+ * the message using the radio.
+ */
+ public static final int SEND_STATUS_ERROR_FALLBACK = 4;
+
+ /**
+ * Message was delivered successfully.
+ */
+ public static final int DELIVER_STATUS_OK = 1;
+
+ /**
+ * Message was not delivered.
+ */
+ public static final int DELIVER_STATUS_ERROR = 2;
+
+ // Lock for feature synchronization
+ private final Object mLock = new Object();
+ private ISmsListener mSmsListener;
+
+ private final IImsSmsFeature mIImsSmsBinder = new IImsSmsFeature.Stub() {
+ @Override
+ public void registerSmsListener(ISmsListener listener) {
+ synchronized (mLock) {
+ SmsFeature.this.registerSmsListener(listener);
+ }
+ }
+
+ @Override
+ public void sendSms(int format, int messageRef, boolean retry, byte[] pdu) {
+ synchronized (mLock) {
+ SmsFeature.this.sendSms(format, messageRef, retry, pdu);
+ }
+ }
+
+ @Override
+ public void acknowledgeSms(int messageRef, int result) {
+ synchronized (mLock) {
+ SmsFeature.this.acknowledgeSms(messageRef, result);
+ }
+ }
+
+ @Override
+ public int getSmsFormat() {
+ synchronized (mLock) {
+ return SmsFeature.this.getSmsFormat();
+ }
+ }
+ };
+
+ /**
+ * Registers a listener responsible for handling tasks like delivering messages.
+
+ * @param listener listener to register.
+ *
+ * @hide
+ */
+ @SystemApi
+ public final void registerSmsListener(ISmsListener listener) {
+ synchronized (mLock) {
+ mSmsListener = listener;
+ }
+ }
+
+ /**
+ * This method will be triggered by the platform when the user attempts to send an SMS. This
+ * method should be implemented by the IMS providers to provide implementation of sending an SMS
+ * over IMS.
+ *
+ * @param format the format of the message. One of {@link #IMS_SMS_FORMAT_3GPP} or
+ * {@link #IMS_SMS_FORMAT_3GPP2}
+ * @param messageRef the message reference.
+ * @param retry whether it is a retry of an already attempted message or not.
+ * @param pdu PDUs representing the contents of the message.
+ */
+ public void sendSms(int format, int messageRef, boolean isRetry, byte[] pdu) {
+ }
+
+ /**
+ * This method will be triggered by the platform after {@link #deliverSms(int, byte[])} has been
+ * called to deliver the result to the IMS provider. It will also be triggered after
+ * {@link #setSentSmsResult(int, int)} has been called to provide the result of the operation.
+ *
+ * @param result Should be {@link #DELIVER_STATUS_OK} if the message was delivered successfully,
+ * {@link #DELIVER_STATUS_ERROR} otherwise.
+ * @param messageRef the message reference.
+ */
+ public void acknowledgeSms(int messageRef, int result) {
+
+ }
+
+ /**
+ * This method should be triggered by the IMS providers when there is an incoming message. The
+ * platform will deliver the message to the messages database and notify the IMS provider of the
+ * result by calling {@link #acknowledgeSms(int)}.
+ *
+ * This method must not be called before {@link #onFeatureReady()} is called.
+ *
+ * @param format the format of the message.One of {@link #IMS_SMS_FORMAT_3GPP} or
+ * {@link #IMS_SMS_FORMAT_3GPP2}
+ * @param pdu PDUs representing the contents of the message.
+ * @throws IllegalStateException if called before {@link #onFeatureReady()}
+ */
+ public final void deliverSms(int format, byte[] pdu) throws IllegalStateException {
+ // TODO: Guard against NPE/ Check if feature is ready and thrown an exception
+ // otherwise.
+ try {
+ mSmsListener.deliverSms(format, pdu);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * This method should be triggered by the IMS providers to pass the result of the sent message
+ * to the platform.
+ *
+ * This method must not be called before {@link #onFeatureReady()} is called.
+ *
+ * @param messageRef the message reference.
+ * @param result One of {@link #SEND_STATUS_OK}, {@link #SEND_STATUS_ERROR},
+ * {@link #SEND_STATUS_ERROR_RETRY}, {@link #SEND_STATUS_ERROR_FALLBACK}
+ * @throws IllegalStateException if called before {@link #onFeatureReady()}
+ */
+ public final void setSentSmsResult(int messageRef, int result) throws IllegalStateException {
+ // TODO: Guard against NPE/ Check if feature is ready and thrown an exception
+ // otherwise.
+ try {
+ mSmsListener.setSentSmsResult(messageRef, result);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Sets the status report of the sent message.
+ *
+ * @param format Should be {@link #IMS_SMS_FORMAT_3GPP} or {@link #IMS_SMS_FORMAT_3GPP2}
+ * @param pdu PDUs representing the content of the status report.
+ * @throws IllegalStateException if called before {@link #onFeatureReady()}
+ */
+ public final void setSentSmsStatusReport(int format, byte[] pdu) {
+ // TODO: Guard against NPE/ Check if feature is ready and thrown an exception
+ // otherwise.
+ try {
+ mSmsListener.setSentSmsStatusReport(format, pdu);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Returns the SMS format. Default is {@link #IMS_SMS_FORMAT_3GPP} unless overridden by IMS
+ * Provider.
+ *
+ * @return sms format.
+ */
+ public int getSmsFormat() {
+ return IMS_SMS_FORMAT_3GPP;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onFeatureReady() {
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onFeatureRemoved() {
+
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public final IImsSmsFeature getBinder() {
+ return mIImsSmsBinder;
+ }
+}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
index dc74094..054a8b2 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -53,6 +53,15 @@
}
/**
+ * Retrieves the configuration of the call barring for specified service class.
+ */
+ @Override
+ public int queryCallBarringForServiceClass(int cbType, int serviceClass)
+ throws RemoteException {
+ return -1;
+ }
+
+ /**
* Retrieves the configuration of the call forward.
*/
@Override
@@ -117,6 +126,15 @@
}
/**
+ * Updates the configuration of the call barring for specified service class.
+ */
+ @Override
+ public int updateCallBarringForServiceClass(int cbType, int action, String[] barrList,
+ int serviceClass) throws RemoteException {
+ return -1;
+ }
+
+ /**
* Updates the configuration of the call forward.
*/
@Override
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java
index b371efb..daa74c8 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java
@@ -21,6 +21,7 @@
import com.android.ims.ImsCallForwardInfo;
import com.android.ims.ImsReasonInfo;
+import com.android.ims.ImsSsData;
import com.android.ims.ImsSsInfo;
import com.android.ims.internal.IImsUt;
import com.android.ims.internal.IImsUtListener;
@@ -85,4 +86,10 @@
public void utConfigurationCallWaitingQueried(IImsUt ut, int id, ImsSsInfo[] cwInfo)
throws RemoteException {
}
+
+ /**
+ * Notifies client when Supplementary Service indication is received
+ */
+ @Override
+ public void onSupplementaryServiceIndication(ImsSsData ssData) {}
}
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index cdfc1fd..6ad54c1 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -111,6 +111,16 @@
// and this capability is not supported by the network.
public static final int CODE_IMEI_NOT_ACCEPTED = 243;
+ //STK CC errors
+ public static final int CODE_DIAL_MODIFIED_TO_USSD = 244;
+ public static final int CODE_DIAL_MODIFIED_TO_SS = 245;
+ public static final int CODE_DIAL_MODIFIED_TO_DIAL = 246;
+ public static final int CODE_DIAL_MODIFIED_TO_DIAL_VIDEO = 247;
+ public static final int CODE_DIAL_VIDEO_MODIFIED_TO_DIAL = 248;
+ public static final int CODE_DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO = 249;
+ public static final int CODE_DIAL_VIDEO_MODIFIED_TO_SS = 250;
+ public static final int CODE_DIAL_VIDEO_MODIFIED_TO_USSD = 251;
+
/**
* STATUSCODE (SIP response code) (IMS -> Telephony)
*/
@@ -217,6 +227,11 @@
public static final int CODE_UT_OPERATION_NOT_ALLOWED = 803;
public static final int CODE_UT_NETWORK_ERROR = 804;
public static final int CODE_UT_CB_PASSWORD_MISMATCH = 821;
+ //STK CC errors
+ public static final int CODE_UT_SS_MODIFIED_TO_DIAL = 822;
+ public static final int CODE_UT_SS_MODIFIED_TO_USSD = 823;
+ public static final int CODE_UT_SS_MODIFIED_TO_SS = 824;
+ public static final int CODE_UT_SS_MODIFIED_TO_DIAL_VIDEO = 825;
/**
* ECBM
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/telephony/java/com/android/ims/ImsSsData.aidl
similarity index 71%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to telephony/java/com/android/ims/ImsSsData.aidl
index 4ccdea5..33f8306 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/telephony/java/com/android/ims/ImsSsData.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,11 +14,6 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+package com.android.ims;
-import android.telephony.SubscriptionInfo;
-
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
-}
-
+parcelable ImsSsData;
diff --git a/telephony/java/com/android/ims/ImsSsData.java b/telephony/java/com/android/ims/ImsSsData.java
new file mode 100644
index 0000000..7336c13
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsSsData.java
@@ -0,0 +1,189 @@
+/*
+ * 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.ims;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+
+/**
+ * Provided STK Call Control Suplementary Service information
+ *
+ * {@hide}
+ */
+public class ImsSsData implements Parcelable {
+
+ //ServiceType
+ public static final int SS_CFU = 0;
+ public static final int SS_CF_BUSY = 1;
+ public static final int SS_CF_NO_REPLY = 2;
+ public static final int SS_CF_NOT_REACHABLE = 3;
+ public static final int SS_CF_ALL = 4;
+ public static final int SS_CF_ALL_CONDITIONAL = 5;
+ public static final int SS_CFUT = 6;
+ public static final int SS_CLIP = 7;
+ public static final int SS_CLIR = 8;
+ public static final int SS_COLP = 9;
+ public static final int SS_COLR = 10;
+ public static final int SS_CNAP = 11;
+ public static final int SS_WAIT = 12;
+ public static final int SS_BAOC = 13;
+ public static final int SS_BAOIC = 14;
+ public static final int SS_BAOIC_EXC_HOME = 15;
+ public static final int SS_BAIC = 16;
+ public static final int SS_BAIC_ROAMING = 17;
+ public static final int SS_ALL_BARRING = 18;
+ public static final int SS_OUTGOING_BARRING = 19;
+ public static final int SS_INCOMING_BARRING = 20;
+ public static final int SS_INCOMING_BARRING_DN = 21;
+ public static final int SS_INCOMING_BARRING_ANONYMOUS = 22;
+
+ //SSRequestType
+ public static final int SS_ACTIVATION = 0;
+ public static final int SS_DEACTIVATION = 1;
+ public static final int SS_INTERROGATION = 2;
+ public static final int SS_REGISTRATION = 3;
+ public static final int SS_ERASURE = 4;
+
+ //TeleserviceType
+ public static final int SS_ALL_TELE_AND_BEARER_SERVICES = 0;
+ public static final int SS_ALL_TELESEVICES = 1;
+ public static final int SS_TELEPHONY = 2;
+ public static final int SS_ALL_DATA_TELESERVICES = 3;
+ public static final int SS_SMS_SERVICES = 4;
+ public static final int SS_ALL_TELESERVICES_EXCEPT_SMS = 5;
+
+ // Refer to ServiceType
+ public int serviceType;
+ // Refere to SSRequestType
+ public int requestType;
+ // Refer to TeleserviceType
+ public int teleserviceType;
+ // Service Class
+ public int serviceClass;
+ // Error information
+ public int result;
+
+ public int[] ssInfo; /* Valid for all supplementary services.
+ This field will be empty for RequestType SS_INTERROGATION
+ and ServiceType SS_CF_*, SS_INCOMING_BARRING_DN,
+ SS_INCOMING_BARRING_ANONYMOUS.*/
+
+ public ImsCallForwardInfo[] cfInfo; /* Valid only for supplementary services
+ ServiceType SS_CF_* and RequestType SS_INTERROGATION */
+
+ public ImsSsInfo[] imsSsInfo; /* Valid only for ServiceType SS_INCOMING_BARRING_DN and
+ ServiceType SS_INCOMING_BARRING_ANONYMOUS */
+
+ public ImsSsData() {}
+
+ public ImsSsData(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public static final Creator<ImsSsData> CREATOR = new Creator<ImsSsData>() {
+ @Override
+ public ImsSsData createFromParcel(Parcel in) {
+ return new ImsSsData(in);
+ }
+
+ @Override
+ public ImsSsData[] newArray(int size) {
+ return new ImsSsData[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(serviceType);
+ out.writeInt(requestType);
+ out.writeInt(teleserviceType);
+ out.writeInt(serviceClass);
+ out.writeInt(result);
+ out.writeIntArray(ssInfo);
+ out.writeParcelableArray(cfInfo, 0);
+ }
+
+ private void readFromParcel(Parcel in) {
+ serviceType = in.readInt();
+ requestType = in.readInt();
+ teleserviceType = in.readInt();
+ serviceClass = in.readInt();
+ result = in.readInt();
+ ssInfo = in.createIntArray();
+ cfInfo = (ImsCallForwardInfo[])in.readParcelableArray(this.getClass().getClassLoader());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public boolean isTypeCF() {
+ return (serviceType == SS_CFU || serviceType == SS_CF_BUSY ||
+ serviceType == SS_CF_NO_REPLY || serviceType == SS_CF_NOT_REACHABLE ||
+ serviceType == SS_CF_ALL || serviceType == SS_CF_ALL_CONDITIONAL);
+ }
+
+ public boolean isTypeUnConditional() {
+ return (serviceType == SS_CFU || serviceType == SS_CF_ALL);
+ }
+
+ public boolean isTypeCW() {
+ return (serviceType == SS_WAIT);
+ }
+
+ public boolean isTypeClip() {
+ return (serviceType == SS_CLIP);
+ }
+
+ public boolean isTypeColr() {
+ return (serviceType == SS_COLR);
+ }
+
+ public boolean isTypeColp() {
+ return (serviceType == SS_COLP);
+ }
+
+ public boolean isTypeClir() {
+ return (serviceType == SS_CLIR);
+ }
+
+ public boolean isTypeIcb() {
+ return (serviceType == SS_INCOMING_BARRING_DN ||
+ serviceType == SS_INCOMING_BARRING_ANONYMOUS);
+ }
+
+ public boolean isTypeBarring() {
+ return (serviceType == SS_BAOC || serviceType == SS_BAOIC ||
+ serviceType == SS_BAOIC_EXC_HOME || serviceType == SS_BAIC ||
+ serviceType == SS_BAIC_ROAMING || serviceType == SS_ALL_BARRING ||
+ serviceType == SS_OUTGOING_BARRING || serviceType == SS_INCOMING_BARRING);
+ }
+
+ public boolean isTypeInterrogation() {
+ return (requestType == SS_INTERROGATION);
+ }
+
+ public String toString() {
+ return "[ImsSsData] " + "ServiceType: " + serviceType
+ + " RequestType: " + requestType
+ + " TeleserviceType: " + teleserviceType
+ + " ServiceClass: " + serviceClass
+ + " Result: " + result;
+ }
+}
diff --git a/telephony/java/com/android/ims/ImsUtInterface.java b/telephony/java/com/android/ims/ImsUtInterface.java
index 5984e78..14c184a 100644
--- a/telephony/java/com/android/ims/ImsUtInterface.java
+++ b/telephony/java/com/android/ims/ImsUtInterface.java
@@ -16,6 +16,7 @@
package com.android.ims;
+import android.os.Handler;
import android.os.Message;
/**
@@ -109,6 +110,12 @@
public void queryCallBarring(int cbType, Message result);
/**
+ * Retrieves the configuration of the call barring for specified service class.
+ * The return value of ((AsyncResult)result.obj) is an array of {@link ImsSsInfo}.
+ */
+ public void queryCallBarring(int cbType, Message result, int serviceClass);
+
+ /**
* Retrieves the configuration of the call forward.
* The return value of ((AsyncResult)result.obj) is an array of {@link ImsCallForwardInfo}.
*/
@@ -147,6 +154,12 @@
Message result, String[] barrList);
/**
+ * Modifies the configuration of the call barring for specified service class.
+ */
+ public void updateCallBarring(int cbType, int action, Message result,
+ String[] barrList, int serviceClass);
+
+ /**
* Modifies the configuration of the call forward.
*/
public void updateCallForward(int action, int condition, String number,
@@ -176,4 +189,18 @@
* Updates the configuration of the COLP supplementary service.
*/
public void updateCOLP(boolean enable, Message result);
+
+ /**
+ * Register for UNSOL_ON_SS indications.
+ * @param handler the {@link Handler} that is notified when there is an ss indication.
+ * @param event Supplimentary service indication event.
+ * @param Object user object.
+ */
+ public void registerForSuppServiceIndication(Handler handler, int event, Object object);
+
+ /**
+ * Deregister for UNSOL_ON_SS indications.
+ * @param handler the {@link Handler} that is notified when there is an ss indication.
+ */
+ public void unregisterForSuppServiceIndication(Handler handler);
}
diff --git a/telephony/java/com/android/ims/internal/IImsSmsFeature.aidl b/telephony/java/com/android/ims/internal/IImsSmsFeature.aidl
new file mode 100644
index 0000000..5068128
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/IImsSmsFeature.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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.ims.internal;
+
+import com.android.ims.internal.ISmsListener;
+
+/**
+ * See SmsFeature for more information.
+ *
+ * {@hide}
+ */
+interface IImsSmsFeature {
+ void registerSmsListener(in ISmsListener listener);
+ void sendSms(in int format, in int messageRef, in boolean retry, in byte[] pdu);
+ void acknowledgeSms(in int messageRef, in int result);
+ int getSmsFormat();
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/IImsUt.aidl b/telephony/java/com/android/ims/internal/IImsUt.aidl
index 4ab5ee3..4f97cc5 100644
--- a/telephony/java/com/android/ims/internal/IImsUt.aidl
+++ b/telephony/java/com/android/ims/internal/IImsUt.aidl
@@ -111,4 +111,15 @@
* Sets the listener.
*/
void setListener(in IImsUtListener listener);
+
+ /**
+ * Retrieves the configuration of the call barring for specified service class.
+ */
+ int queryCallBarringForServiceClass(int cbType, int serviceClass);
+
+ /**
+ * Updates the configuration of the call barring for specified service class.
+ */
+ int updateCallBarringForServiceClass(int cbType, int action, in String[] barrList,
+ int serviceClass);
}
diff --git a/telephony/java/com/android/ims/internal/IImsUtListener.aidl b/telephony/java/com/android/ims/internal/IImsUtListener.aidl
index 300273a..1bc0369 100644
--- a/telephony/java/com/android/ims/internal/IImsUtListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsUtListener.aidl
@@ -19,6 +19,7 @@
import android.os.Bundle;
import com.android.ims.ImsCallForwardInfo;
+import com.android.ims.ImsSsData;
import com.android.ims.ImsSsInfo;
import com.android.ims.internal.IImsUt;
import com.android.ims.ImsReasonInfo;
@@ -56,4 +57,11 @@
*/
void utConfigurationCallWaitingQueried(in IImsUt ut,
int id, in ImsSsInfo[] cwInfo);
+
+ /**
+ * Notifies client when Supplementary Service indication is received
+ *
+ * @param ssData Details of SS request and response information
+ */
+ void onSupplementaryServiceIndication(in ImsSsData ssData);
}
diff --git a/core/java/android/print/IPrintClient.aidl b/telephony/java/com/android/ims/internal/ISmsListener.aidl
similarity index 62%
copy from core/java/android/print/IPrintClient.aidl
copy to telephony/java/com/android/ims/internal/ISmsListener.aidl
index 3f39d08..1266f04 100644
--- a/core/java/android/print/IPrintClient.aidl
+++ b/telephony/java/com/android/ims/internal/ISmsListener.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -14,17 +14,14 @@
* limitations under the License.
*/
-package android.print;
-
-import android.content.IntentSender;
+package com.android.ims.internal;
/**
- * Interface for communication with a printing app.
- *
- * @see android.print.IPrintClientCallback
- *
- * @hide
+ * See SmsFeature for more information.
+ * {@hide}
*/
-oneway interface IPrintClient {
- void startPrintJobConfigActivity(in IntentSender intent);
-}
+interface ISmsListener {
+ void setSentSmsResult(in int messageRef, in int result);
+ void setSentSmsStatusReport(in int format, in byte[] pdu);
+ void deliverSms(in int format, in byte[] pdu);
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/internal/telephony/ICallService.aidl b/telephony/java/com/android/internal/telephony/ICallService.aidl
deleted file mode 100644
index cb9b2e8..0000000
--- a/telephony/java/com/android/internal/telephony/ICallService.aidl
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-import com.android.internal.telephony.ICallServiceAdapter;
-
-/**
- * Service interface for services which would like to provide calls to be
- * managed by the system in-call UI.
- *
- * This interface provides methods that the android framework can use to deliver commands
- * for calls provided by this call service including making new calls and disconnecting
- * existing ones. A binding to ICallService implementations exists for two conditions:
- * 1) There exists one or more live calls for that call service,
- * 2) Prior to an outbound call to test if this call service is compatible with the outgoing call.
- */
-oneway interface ICallService {
-
- /**
- * Determines if the CallService can make calls to the handle.
- * TODO(santoscordon): Move this method into its own service interface long term.
- * TODO(santoscordon): Add response callback parameter.
- */
- void isCompatibleWith(String handle);
-
- /**
- * Attempts to call the relevant party using the specified handle, be it a phone number,
- * SIP address, or some other kind of user ID. Note that the set of handle types is
- * dynamically extensible since call providers should be able to implement arbitrary
- * handle-calling systems. See {@link #isCompatibleWith}.
- * TODO(santoscordon): Should this have a response attached to it to ensure that the call
- * service actually plans to make the call?
- */
- void call(String handle);
-
- /**
- * Disconnects the call identified by callId.
- */
- void disconnect(String callId);
-
- /**
- * Sets an implementation of ICallServiceAdapter which the call service can use to add new calls
- * and communicate state changes of existing calls. This is the first method that is called
- * after a the framework binds to the call service.
- */
- void setCallServiceAdapter(ICallServiceAdapter callServiceAdapter);
-}
diff --git a/telephony/java/com/android/internal/telephony/ICallServiceAdapter.aidl b/telephony/java/com/android/internal/telephony/ICallServiceAdapter.aidl
deleted file mode 100644
index bc900f0..0000000
--- a/telephony/java/com/android/internal/telephony/ICallServiceAdapter.aidl
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-import com.android.internal.telephony.CallInfo;
-
-/**
- * Provides methods for ICallService implementations to interact with the system phone app.
- */
-oneway interface ICallServiceAdapter {
-
- /**
- * Retrieves a new unique call id for use with newOutgoingCall and newIncomingCall.
- */
- void getNextCallId(/* TODO(santoscordon): Needs response object */);
-
- /**
- * Tells CallsManager of a new incoming call.
- */
- void newIncomingCall(String callId, in CallInfo info);
-
- /**
- * Tells CallsManager of a new outgoing call.
- */
- void newOutgoingCall(String callId, in CallInfo info);
-
- /**
- * Sets a call's state to active (e.g., an ongoing call where two parties can actively
- * communicate).
- */
- void setActive(String callId);
-
- /**
- * Sets a call's state to ringing (e.g., an inbound ringing call).
- */
- void setRinging(String callId);
-
- /**
- * Sets a call's state to dialing (e.g., dialing an outbound call).
- */
- void setDialing(String callId);
-
- /**
- * Sets a call's state to disconnected.
- */
- void setDisconnected(String callId);
-}
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 644ad49..5e015e0 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -18,7 +18,6 @@
import android.app.PendingIntent;
import android.telephony.SubscriptionInfo;
-import com.android.internal.telephony.ISubscriptionListener;
interface ISub {
/**
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java
index 5f2e561..d27a758 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java
@@ -18,6 +18,7 @@
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;
@@ -113,8 +114,8 @@
* share code and logic with GSM. Also, gather all DTMF/BCD
* processing code in one place.
*/
-
- private static byte[] parseToDtmf(String address) {
+ @VisibleForTesting
+ public static byte[] parseToDtmf(String address) {
int digits = address.length();
byte[] result = new byte[digits];
for (int i = 0; i < digits; i++) {
@@ -196,33 +197,46 @@
public static CdmaSmsAddress parse(String address) {
CdmaSmsAddress addr = new CdmaSmsAddress();
addr.address = address;
- addr.ton = CdmaSmsAddress.TON_UNKNOWN;
- byte[] origBytes = null;
+ addr.ton = TON_UNKNOWN;
+ addr.digitMode = DIGIT_MODE_4BIT_DTMF;
+ addr.numberPlan = NUMBERING_PLAN_UNKNOWN;
+ addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
+
+ byte[] origBytes;
String filteredAddr = filterNumericSugar(address);
- if (filteredAddr != null) {
- origBytes = parseToDtmf(filteredAddr);
- }
- if (origBytes != null) {
- addr.digitMode = DIGIT_MODE_4BIT_DTMF;
- addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
- if (address.indexOf('+') != -1) {
- addr.ton = TON_INTERNATIONAL_OR_IP;
- }
- } else {
- filteredAddr = filterWhitespace(address);
- origBytes = UserData.stringToAscii(filteredAddr);
- if (origBytes == null) {
- return null;
- }
+ if (address.contains("+") || filteredAddr == null) {
+ // 3GPP2 C.S0015-B section 3.4.3.3 Address Parameters
+ // NUMBER_MODE should set to 1 for network address and email address.
addr.digitMode = DIGIT_MODE_8BIT_CHAR;
addr.numberMode = NUMBER_MODE_DATA_NETWORK;
- if (address.indexOf('@') != -1) {
+ filteredAddr = filterWhitespace(address);
+
+ if (address.contains("@")) {
+ // This is an email address
addr.ton = TON_NATIONAL_OR_EMAIL;
+ } else if (address.contains("+") && filterNumericSugar(address) != null) {
+ // This is an international number
+ // 3GPP2 C.S0015-B section 3.4.3.3 Address Parameters
+ // digit mode is set to 1 and number mode is set to 0, type of number should set
+ // to the value correspond to the value in 3GPP2 C.S005-D, table2.7.1.3.2.4-2
+ addr.ton = TON_INTERNATIONAL_OR_IP;
+ addr.numberPlan = NUMBERING_PLAN_ISDN_TELEPHONY;
+ addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
+ filteredAddr = filterNumericSugar(address);
}
+
+ origBytes = UserData.stringToAscii(filteredAddr);
+ } else {
+ // The address is not an international number and it only contains digit and *#
+ origBytes = parseToDtmf(filteredAddr);
}
+
+ if (origBytes == null) {
+ return null;
+ }
+
addr.origBytes = origBytes;
addr.numberOfDigits = origBytes.length;
return addr;
}
-
}
diff --git a/test-base/Android.mk b/test-base/Android.mk
new file mode 100644
index 0000000..03bdcf23
--- /dev/null
+++ b/test-base/Android.mk
@@ -0,0 +1,198 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+# Build the android.test.base library
+# ===================================
+# This contains the junit.framework and android.test classes that were in
+# Android API level 25 excluding those from android.test.runner.
+# Also contains the com.android.internal.util.Predicate[s] classes.
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := android.test.base
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
+
+include $(BUILD_JAVA_LIBRARY)
+
+# Build the legacy-test library
+# =============================
+# This contains the junit.framework and android.test classes that were in
+# Android API level 25 excluding those from android.test.runner.
+# Also contains the com.android.internal.util.Predicate[s] classes.
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := legacy-test
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
+
+include $(BUILD_JAVA_LIBRARY)
+
+# Build the repackaged.android.test.base library
+# ==============================================
+# This contains repackaged versions of the classes from legacy-test.
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := repackaged.android.test.base
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
+LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# For unbundled build we'll use the prebuilt jar from prebuilts/sdk.
+ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))
+
+# Generate the stub source files for android.test.base.stubs
+# ==========================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := \
+ core-oj \
+ core-libart \
+ framework \
+
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/src
+
+ANDROID_TEST_BASE_OUTPUT_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.base.stubs_intermediates/api.txt
+ANDROID_TEST_BASE_OUTPUT_REMOVED_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.base.stubs_intermediates/removed.txt
+
+ANDROID_TEST_BASE_API_FILE := $(LOCAL_PATH)/api/android-test-base-current.txt
+ANDROID_TEST_BASE_REMOVED_API_FILE := $(LOCAL_PATH)/api/android-test-base-removed.txt
+
+LOCAL_DROIDDOC_OPTIONS:= \
+ -stubpackages android.test:android.test.suitebuilder.annotation:com.android.internal.util:junit.framework \
+ -stubsourceonly \
+ -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.base.stubs_intermediates/src \
+ -nodocs \
+ -api $(ANDROID_TEST_BASE_OUTPUT_API_FILE) \
+ -removedApi $(ANDROID_TEST_BASE_OUTPUT_REMOVED_API_FILE) \
+
+LOCAL_UNINSTALLABLE_MODULE := true
+LOCAL_MODULE := android-test-base-api-stubs-gen
+
+include $(BUILD_DROIDDOC)
+
+# Remember the target that will trigger the code generation.
+android_test_base_gen_stamp := $(full_target)
+
+# Add some additional dependencies
+$(ANDROID_TEST_BASE_OUTPUT_API_FILE): $(full_target)
+$(ANDROID_TEST_BASE_OUTPUT_REMOVED_API_FILE): $(full_target)
+
+# Build the android.test.base.stubs library
+# =========================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := android.test.base.stubs
+
+LOCAL_SOURCE_FILES_ALL_GENERATED := true
+LOCAL_SDK_VERSION := current
+
+# Make sure to run droiddoc first to generate the stub source files.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(android_test_base_gen_stamp)
+android_test_base_gen_stamp :=
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Archive a copy of the classes.jar in SDK build.
+$(call dist-for-goals,sdk win_sdk,$(full_classes_jar):android.test.base.stubs.jar)
+
+# Check that the android.test.base.stubs library has not changed
+# ==============================================================
+
+# Check that the API we're building hasn't changed from the not-yet-released
+# SDK version.
+$(eval $(call check-api, \
+ check-android-test-base-api-current, \
+ $(ANDROID_TEST_BASE_API_FILE), \
+ $(ANDROID_TEST_BASE_OUTPUT_API_FILE), \
+ $(ANDROID_TEST_BASE_REMOVED_API_FILE), \
+ $(ANDROID_TEST_BASE_OUTPUT_REMOVED_API_FILE), \
+ -error 2 -error 3 -error 4 -error 5 -error 6 \
+ -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
+ -error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 \
+ -error 25 -error 26 -error 27, \
+ cat $(LOCAL_PATH)/api/apicheck_msg_android_test_base.txt, \
+ check-android-test-base-api, \
+ $(call doc-timestamp-for,android-test-base-api-stubs-gen) \
+ ))
+
+.PHONY: check-android-test-base-api
+checkapi: check-android-test-base-api
+
+.PHONY: update-android-test-base-api
+update-api: update-android-test-base-api
+
+update-android-test-base-api: $(ANDROID_TEST_BASE_OUTPUT_API_FILE) | $(ACP)
+ @echo Copying current.txt
+ $(hide) $(ACP) $(ANDROID_TEST_BASE_OUTPUT_API_FILE) $(ANDROID_TEST_BASE_API_FILE)
+ @echo Copying removed.txt
+ $(hide) $(ACP) $(ANDROID_TEST_BASE_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_BASE_REMOVED_API_FILE)
+
+endif # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
+
+# Build the legacy-android-test library
+# =====================================
+# This contains the android.test classes that were in Android API level 25,
+# including those from android.test.runner.
+# Also contains the com.android.internal.util.Predicate[s] classes.
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, src/android) \
+ $(call all-java-files-under, ../test-runner/src/android) \
+ $(call all-java-files-under, ../test-mock/src/android) \
+ $(call all-java-files-under, src/com)
+LOCAL_MODULE := legacy-android-test
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj core-libart framework junit
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Build the legacy.test.stubs library
+# ===================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := legacy.test.stubs
+LOCAL_SDK_VERSION := current
+
+LOCAL_STATIC_JAVA_LIBRARIES := android.test.base.stubs
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+ifeq ($(HOST_OS),linux)
+# Build the legacy-performance-test-hostdex library
+# =================================================
+# This contains the android.test.PerformanceTestCase class only
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := src/android/test/PerformanceTestCase.java
+LOCAL_MODULE := legacy-performance-test-hostdex
+
+include $(BUILD_HOST_DALVIK_STATIC_JAVA_LIBRARY)
+endif # HOST_OS == linux
diff --git a/legacy-test/api/legacy-test-current.txt b/test-base/api/android-test-base-current.txt
similarity index 100%
rename from legacy-test/api/legacy-test-current.txt
rename to test-base/api/android-test-base-current.txt
diff --git a/legacy-test/api/legacy-test-removed.txt b/test-base/api/android-test-base-removed.txt
similarity index 100%
rename from legacy-test/api/legacy-test-removed.txt
rename to test-base/api/android-test-base-removed.txt
diff --git a/test-base/api/apicheck_msg_android_test_base.txt b/test-base/api/apicheck_msg_android_test_base.txt
new file mode 100644
index 0000000..144aecc
--- /dev/null
+++ b/test-base/api/apicheck_msg_android_test_base.txt
@@ -0,0 +1,17 @@
+
+******************************
+You have tried to change the API from what has been previously approved.
+
+To make these errors go away, you have two choices:
+ 1) You can add "@hide" javadoc comments to the methods, etc. listed in the
+ errors above.
+
+ 2) You can update android-test-base-current.txt by executing the following command:
+ make update-android-test-base-api
+
+ To submit the revised android-test-base-current.txt to the main Android repository,
+ you will need approval.
+******************************
+
+
+
diff --git a/legacy-test/jarjar-rules.txt b/test-base/jarjar-rules.txt
similarity index 100%
rename from legacy-test/jarjar-rules.txt
rename to test-base/jarjar-rules.txt
diff --git a/legacy-test/src/android/test/AndroidTestCase.java b/test-base/src/android/test/AndroidTestCase.java
similarity index 100%
rename from legacy-test/src/android/test/AndroidTestCase.java
rename to test-base/src/android/test/AndroidTestCase.java
diff --git a/legacy-test/src/android/test/FlakyTest.java b/test-base/src/android/test/FlakyTest.java
similarity index 100%
rename from legacy-test/src/android/test/FlakyTest.java
rename to test-base/src/android/test/FlakyTest.java
diff --git a/legacy-test/src/android/test/InstrumentationTestCase.java b/test-base/src/android/test/InstrumentationTestCase.java
similarity index 100%
rename from legacy-test/src/android/test/InstrumentationTestCase.java
rename to test-base/src/android/test/InstrumentationTestCase.java
diff --git a/legacy-test/src/android/test/InstrumentationTestSuite.java b/test-base/src/android/test/InstrumentationTestSuite.java
similarity index 100%
rename from legacy-test/src/android/test/InstrumentationTestSuite.java
rename to test-base/src/android/test/InstrumentationTestSuite.java
diff --git a/legacy-test/src/android/test/PerformanceTestCase.java b/test-base/src/android/test/PerformanceTestCase.java
similarity index 100%
rename from legacy-test/src/android/test/PerformanceTestCase.java
rename to test-base/src/android/test/PerformanceTestCase.java
diff --git a/legacy-test/src/android/test/RepetitiveTest.java b/test-base/src/android/test/RepetitiveTest.java
similarity index 100%
rename from legacy-test/src/android/test/RepetitiveTest.java
rename to test-base/src/android/test/RepetitiveTest.java
diff --git a/legacy-test/src/android/test/UiThreadTest.java b/test-base/src/android/test/UiThreadTest.java
similarity index 100%
rename from legacy-test/src/android/test/UiThreadTest.java
rename to test-base/src/android/test/UiThreadTest.java
diff --git a/legacy-test/src/android/test/package.html b/test-base/src/android/test/package.html
similarity index 100%
rename from legacy-test/src/android/test/package.html
rename to test-base/src/android/test/package.html
diff --git a/legacy-test/src/android/test/suitebuilder/annotation/LargeTest.java b/test-base/src/android/test/suitebuilder/annotation/LargeTest.java
similarity index 100%
rename from legacy-test/src/android/test/suitebuilder/annotation/LargeTest.java
rename to test-base/src/android/test/suitebuilder/annotation/LargeTest.java
diff --git a/legacy-test/src/android/test/suitebuilder/annotation/MediumTest.java b/test-base/src/android/test/suitebuilder/annotation/MediumTest.java
similarity index 100%
rename from legacy-test/src/android/test/suitebuilder/annotation/MediumTest.java
rename to test-base/src/android/test/suitebuilder/annotation/MediumTest.java
diff --git a/legacy-test/src/android/test/suitebuilder/annotation/SmallTest.java b/test-base/src/android/test/suitebuilder/annotation/SmallTest.java
similarity index 100%
rename from legacy-test/src/android/test/suitebuilder/annotation/SmallTest.java
rename to test-base/src/android/test/suitebuilder/annotation/SmallTest.java
diff --git a/legacy-test/src/android/test/suitebuilder/annotation/Smoke.java b/test-base/src/android/test/suitebuilder/annotation/Smoke.java
similarity index 100%
rename from legacy-test/src/android/test/suitebuilder/annotation/Smoke.java
rename to test-base/src/android/test/suitebuilder/annotation/Smoke.java
diff --git a/legacy-test/src/android/test/suitebuilder/annotation/Suppress.java b/test-base/src/android/test/suitebuilder/annotation/Suppress.java
similarity index 100%
rename from legacy-test/src/android/test/suitebuilder/annotation/Suppress.java
rename to test-base/src/android/test/suitebuilder/annotation/Suppress.java
diff --git a/legacy-test/src/android/test/suitebuilder/annotation/package.html b/test-base/src/android/test/suitebuilder/annotation/package.html
similarity index 100%
rename from legacy-test/src/android/test/suitebuilder/annotation/package.html
rename to test-base/src/android/test/suitebuilder/annotation/package.html
diff --git a/legacy-test/src/com/android/internal/util/Predicate.java b/test-base/src/com/android/internal/util/Predicate.java
similarity index 100%
rename from legacy-test/src/com/android/internal/util/Predicate.java
rename to test-base/src/com/android/internal/util/Predicate.java
diff --git a/legacy-test/src/junit/MODULE_LICENSE_CPL b/test-base/src/junit/MODULE_LICENSE_CPL
similarity index 100%
rename from legacy-test/src/junit/MODULE_LICENSE_CPL
rename to test-base/src/junit/MODULE_LICENSE_CPL
diff --git a/legacy-test/src/junit/README.android b/test-base/src/junit/README.android
similarity index 100%
rename from legacy-test/src/junit/README.android
rename to test-base/src/junit/README.android
diff --git a/legacy-test/src/junit/cpl-v10.html b/test-base/src/junit/cpl-v10.html
similarity index 100%
rename from legacy-test/src/junit/cpl-v10.html
rename to test-base/src/junit/cpl-v10.html
diff --git a/legacy-test/src/junit/framework/Assert.java b/test-base/src/junit/framework/Assert.java
similarity index 100%
rename from legacy-test/src/junit/framework/Assert.java
rename to test-base/src/junit/framework/Assert.java
diff --git a/legacy-test/src/junit/framework/AssertionFailedError.java b/test-base/src/junit/framework/AssertionFailedError.java
similarity index 100%
rename from legacy-test/src/junit/framework/AssertionFailedError.java
rename to test-base/src/junit/framework/AssertionFailedError.java
diff --git a/legacy-test/src/junit/framework/ComparisonCompactor.java b/test-base/src/junit/framework/ComparisonCompactor.java
similarity index 100%
rename from legacy-test/src/junit/framework/ComparisonCompactor.java
rename to test-base/src/junit/framework/ComparisonCompactor.java
diff --git a/legacy-test/src/junit/framework/ComparisonFailure.java b/test-base/src/junit/framework/ComparisonFailure.java
similarity index 100%
rename from legacy-test/src/junit/framework/ComparisonFailure.java
rename to test-base/src/junit/framework/ComparisonFailure.java
diff --git a/legacy-test/src/junit/framework/Protectable.java b/test-base/src/junit/framework/Protectable.java
similarity index 100%
rename from legacy-test/src/junit/framework/Protectable.java
rename to test-base/src/junit/framework/Protectable.java
diff --git a/legacy-test/src/junit/framework/Test.java b/test-base/src/junit/framework/Test.java
similarity index 100%
rename from legacy-test/src/junit/framework/Test.java
rename to test-base/src/junit/framework/Test.java
diff --git a/legacy-test/src/junit/framework/TestCase.java b/test-base/src/junit/framework/TestCase.java
similarity index 100%
rename from legacy-test/src/junit/framework/TestCase.java
rename to test-base/src/junit/framework/TestCase.java
diff --git a/legacy-test/src/junit/framework/TestFailure.java b/test-base/src/junit/framework/TestFailure.java
similarity index 100%
rename from legacy-test/src/junit/framework/TestFailure.java
rename to test-base/src/junit/framework/TestFailure.java
diff --git a/legacy-test/src/junit/framework/TestListener.java b/test-base/src/junit/framework/TestListener.java
similarity index 100%
rename from legacy-test/src/junit/framework/TestListener.java
rename to test-base/src/junit/framework/TestListener.java
diff --git a/legacy-test/src/junit/framework/TestResult.java b/test-base/src/junit/framework/TestResult.java
similarity index 100%
rename from legacy-test/src/junit/framework/TestResult.java
rename to test-base/src/junit/framework/TestResult.java
diff --git a/legacy-test/src/junit/framework/TestSuite.java b/test-base/src/junit/framework/TestSuite.java
similarity index 100%
rename from legacy-test/src/junit/framework/TestSuite.java
rename to test-base/src/junit/framework/TestSuite.java
diff --git a/test-mock/Android.mk b/test-mock/Android.mk
index 18da8b8..2c07955 100644
--- a/test-mock/Android.mk
+++ b/test-mock/Android.mk
@@ -24,9 +24,9 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework legacy-test
+LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
-LOCAL_JARJAR_RULES := $(LOCAL_PATH)/../legacy-test/jarjar-rules.txt
+LOCAL_JARJAR_RULES := $(LOCAL_PATH)/../test-base/jarjar-rules.txt
LOCAL_MODULE:= repackaged.android.test.mock
@@ -130,15 +130,4 @@
@echo Copying removed.txt
$(hide) $(ACP) $(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_MOCK_REMOVED_API_FILE)
-# Build the android.test.mock.sdk library
-# =======================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := android.test.mock.sdk
-LOCAL_SDK_VERSION := current
-
-LOCAL_STATIC_JAVA_LIBRARIES := android.test.mock.stubs
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
endif # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
diff --git a/test-mock/src/android/test/mock/MockPackageManager.java b/test-mock/src/android/test/mock/MockPackageManager.java
index 0c562e6..ce8019f 100644
--- a/test-mock/src/android/test/mock/MockPackageManager.java
+++ b/test-mock/src/android/test/mock/MockPackageManager.java
@@ -46,6 +46,7 @@
import android.content.pm.SharedLibraryInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VersionedPackage;
+import android.content.pm.dex.ArtManager;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.Rect;
@@ -1174,4 +1175,12 @@
@Nullable DexModuleRegisterCallback callback) {
throw new UnsupportedOperationException();
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public ArtManager getArtManager() {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
index d0f5b32..87fe831 100644
--- a/test-runner/Android.mk
+++ b/test-runner/Android.mk
@@ -26,7 +26,7 @@
core-oj \
core-libart \
framework \
- legacy-test \
+ android.test.base \
android.test.mock \
LOCAL_MODULE:= android.test.runner
@@ -43,10 +43,10 @@
core-oj \
core-libart \
framework \
- legacy-test \
+ android.test.base \
android.test.mock \
-LOCAL_JARJAR_RULES := $(LOCAL_PATH)/../legacy-test/jarjar-rules.txt
+LOCAL_JARJAR_RULES := $(LOCAL_PATH)/../test-base/jarjar-rules.txt
LOCAL_MODULE:= repackaged.android.test.runner
@@ -65,7 +65,7 @@
core-oj \
core-libart \
framework \
- legacy-test \
+ android.test.base \
android.test.mock \
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
@@ -104,7 +104,7 @@
LOCAL_MODULE := android.test.runner.stubs
LOCAL_JAVA_LIBRARIES := \
- legacy.test.stubs \
+ android.test.base.stubs \
android.test.mock.stubs \
LOCAL_SOURCE_FILES_ALL_GENERATED := true
diff --git a/test-runner/api/android-test-runner-current.txt b/test-runner/api/android-test-runner-current.txt
index 905cfe7..1170eb5 100644
--- a/test-runner/api/android-test-runner-current.txt
+++ b/test-runner/api/android-test-runner-current.txt
@@ -271,8 +271,6 @@
public deprecated class TestSuiteBuilder {
ctor public TestSuiteBuilder(java.lang.Class);
ctor public TestSuiteBuilder(java.lang.String, java.lang.ClassLoader);
- method public android.test.suitebuilder.TestSuiteBuilder addRequirements(java.util.List<com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>>);
- method public final android.test.suitebuilder.TestSuiteBuilder addRequirements(com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>...);
method public final junit.framework.TestSuite build();
method public android.test.suitebuilder.TestSuiteBuilder excludePackages(java.lang.String...);
method protected java.lang.String getSuiteName();
diff --git a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
index 6158e0c..2857696 100644
--- a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
+++ b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
@@ -119,6 +119,7 @@
*
* @param predicates Predicates to add to the list of requirements.
* @return The builder for method chaining.
+ * @hide
*/
public TestSuiteBuilder addRequirements(List<Predicate<TestMethod>> predicates) {
this.predicates.addAll(predicates);
@@ -156,7 +157,7 @@
/**
* Override the default name for the suite being built. This should generally be called if you
- * call {@link #addRequirements(com.android.internal.util.Predicate[])} to make it clear which
+ * call {@code addRequirements(com.android.internal.util.Predicate[])} to make it clear which
* tests will be included. The name you specify is automatically prefixed with the package
* containing the tests to be run. If more than one package is specified, the first is used.
*
@@ -215,6 +216,7 @@
*
* @param predicates Predicates to add to the list of requirements.
* @return The builder for method chaining.
+ * @hide
*/
public final TestSuiteBuilder addRequirements(Predicate<TestMethod>... predicates) {
ArrayList<Predicate<TestMethod>> list = new ArrayList<Predicate<TestMethod>>();
diff --git a/tests/AppLaunch/Android.mk b/tests/AppLaunch/Android.mk
index d01b1f9..09739e5 100644
--- a/tests/AppLaunch/Android.mk
+++ b/tests/AppLaunch/Android.mk
@@ -9,7 +9,7 @@
LOCAL_PACKAGE_NAME := AppLaunch
LOCAL_CERTIFICATE := platform
-LOCAL_JAVA_LIBRARIES := legacy-android-test
+LOCAL_JAVA_LIBRARIES := android.test.base android.test.runner
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/Android.mk b/tests/BackgroundDexOptServiceIntegrationTests/Android.mk
new file mode 100644
index 0000000..da1a08b
--- /dev/null
+++ b/tests/BackgroundDexOptServiceIntegrationTests/Android.mk
@@ -0,0 +1,34 @@
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-test \
+
+LOCAL_PACKAGE_NAME := BackgroundDexOptServiceIntegrationTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml b/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml
new file mode 100644
index 0000000..afae155
--- /dev/null
+++ b/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.bgdexopttest">
+
+
+ <!-- Uses API introduced in O (26) -->
+ <uses-sdk
+ android:minSdkVersion="1"
+ android:targetSdkVersion="26" />
+
+ <uses-permission android:name="android.permission.DUMP" />
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
+ <uses-permission android:name="android.permission.SET_TIME" />
+ <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.bgdexopttest"
+ android:label="Integration test for BackgroundDexOptService" />
+</manifest>
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/AndroidTest.xml b/tests/BackgroundDexOptServiceIntegrationTests/AndroidTest.xml
new file mode 100644
index 0000000..9bb1e28
--- /dev/null
+++ b/tests/BackgroundDexOptServiceIntegrationTests/AndroidTest.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs BackgroundDexOptService Integration Tests">
+ <!--DeviceSetup should go before TimeSetter because it stops automatic update of time-->
+ <target_preparer
+ class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="auto-update-time" value="OFF"/>
+ <option name="auto-update-timezone" value="OFF"/>
+ <option name="set-property" key="pm.dexopt.downgrade_after_inactive_days" value="2"/>
+ <option name="set-property" key="pm.dexopt.disable_bg_dexopt" value="true"/>
+ <option name="set-property" key="pm.dexopt.inactive" value="verify"/>
+ <option name="set-property" key="pm.dexopt.bg-dexopt" value="speed"/>
+ <option name="restore-settings" value="true"/>
+ <option name="restore-properties" value="true"/>
+ </target_preparer>
+
+ <!--Test app needs to be installed when we change its settings below-->
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="BackgroundDexOptServiceIntegrationTests.apk"/>
+ <option name="cleanup-apks" value="true"/>
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.SetPackagesRecentlyUsed">
+ <option name="package-recently-used-time" value="0d"/>
+ <option name="package-recently-used-name" value="com.android.frameworks.bgdexopttest"/>
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.RestartSystemServerTargetPreparer"/>
+
+ <target_preparer class="com.android.tradefed.targetprep.DeviceStorageFiller">
+ <!--32GB-->
+ <!--necessary because a package cannot create a file larger than 100GB-->
+ <option name="free-bytes" value="34359738368"/>
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct"/>
+ <option name="test-tag" value="BackgroundDexOptServiceIntegrationTests"/>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.frameworks.bgdexopttest"/>
+ <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
+ </test>
+</configuration>
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java b/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
new file mode 100644
index 0000000..3734412
--- /dev/null
+++ b/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
@@ -0,0 +1,313 @@
+/*
+ * 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.pm;
+
+import android.app.AlarmManager;
+import android.content.Context;
+import android.os.Environment;
+import android.os.SystemProperties;
+import android.os.storage.StorageManager;
+import android.support.test.InstrumentationRegistry;
+import android.util.Log;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Integration tests for {@link BackgroundDexOptService}.
+ *
+ * Tests various scenarios around BackgroundDexOptService.
+ * 1. Under normal conditions, check that dexopt upgrades test app to
+ * $(getprop pm.dexopt.bg-dexopt).
+ * 2. Under low storage conditions and package is unused, check
+ * that dexopt downgrades test app to $(getprop pm.dexopt.inactive).
+ * 3. Under low storage conditions and package is recently used, check
+ * that dexopt upgrades test app to $(getprop pm.dexopt.bg-dexopt).
+ *
+ * Each test case runs "cmd package bg-dexopt-job com.android.frameworks.bgdexopttest".
+ *
+ * The setup for these tests make sure this package has been configured to have been recently used
+ * plus installed far enough in the past. If a test case requires that this package has not been
+ * recently used, it sets the time forward more than
+ * `getprop pm.dexopt.downgrade_after_inactive_days` days.
+ *
+ * For tests that require low storage, the phone is filled up.
+ *
+ * Run with "atest BackgroundDexOptServiceIntegrationTests".
+ */
+@RunWith(JUnit4.class)
+public final class BackgroundDexOptServiceIntegrationTests {
+
+ private static final String TAG = BackgroundDexOptServiceIntegrationTests.class.getSimpleName();
+
+ // Name of package to test on.
+ private static final String PACKAGE_NAME = "com.android.frameworks.bgdexopttest";
+ // Name of file used to fill up storage.
+ private static final String BIG_FILE = "bigfile";
+ private static final String BG_DEXOPT_COMPILER_FILTER = SystemProperties.get(
+ "pm.dexopt.bg-dexopt");
+ private static final String DOWNGRADE_COMPILER_FILTER = SystemProperties.get(
+ "pm.dexopt.inactive");
+ private static final long DOWNGRADE_AFTER_DAYS = SystemProperties.getLong(
+ "pm.dexopt.downgrade_after_inactive_days", 0);
+ // Needs to be between 1.0 and 2.0.
+ private static final double LOW_STORAGE_MULTIPLIER = 1.5;
+
+ // The file used to fill up storage.
+ private File mBigFile;
+
+ // Remember start time.
+ @BeforeClass
+ public static void setUpAll() {
+ if (!SystemProperties.getBoolean("pm.dexopt.disable_bg_dexopt", false)) {
+ throw new RuntimeException(
+ "bg-dexopt is not disabled (set pm.dexopt.disable_bg_dexopt to true)");
+ }
+ if (DOWNGRADE_AFTER_DAYS < 1) {
+ throw new RuntimeException(
+ "pm.dexopt.downgrade_after_inactive_days must be at least 1");
+ }
+ if ("quicken".equals(BG_DEXOPT_COMPILER_FILTER)) {
+ throw new RuntimeException("pm.dexopt.bg-dexopt should not be \"quicken\"");
+ }
+ if ("quicken".equals(DOWNGRADE_COMPILER_FILTER)) {
+ throw new RuntimeException("pm.dexopt.inactive should not be \"quicken\"");
+ }
+ }
+
+
+ private static Context getContext() {
+ return InstrumentationRegistry.getTargetContext();
+ }
+
+ @Before
+ public void setUp() throws IOException {
+ File dataDir = getContext().getDataDir();
+ mBigFile = new File(dataDir, BIG_FILE);
+ }
+
+ @After
+ public void tearDown() {
+ if (mBigFile.exists()) {
+ boolean result = mBigFile.delete();
+ if (!result) {
+ throw new RuntimeException("Couldn't delete big file");
+ }
+ }
+ }
+
+ // Return the content of the InputStream as a String.
+ private static String inputStreamToString(InputStream is) throws IOException {
+ char[] buffer = new char[1024];
+ StringBuilder builder = new StringBuilder();
+ try (InputStreamReader reader = new InputStreamReader(is)) {
+ for (; ; ) {
+ int count = reader.read(buffer, 0, buffer.length);
+ if (count < 0) {
+ break;
+ }
+ builder.append(buffer, 0, count);
+ }
+ }
+ return builder.toString();
+ }
+
+ // Run the command and return the stdout.
+ private static String runShellCommand(String cmd) throws IOException {
+ Log.i(TAG, String.format("running command: '%s'", cmd));
+ long startTime = System.nanoTime();
+ Process p = Runtime.getRuntime().exec(cmd);
+ int res;
+ try {
+ res = p.waitFor();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ String stdout = inputStreamToString(p.getInputStream());
+ String stderr = inputStreamToString(p.getErrorStream());
+ long elapsedTime = System.nanoTime() - startTime;
+ Log.i(TAG, String.format("ran command: '%s' in %d ms with return code %d", cmd,
+ TimeUnit.NANOSECONDS.toMillis(elapsedTime), res));
+ Log.i(TAG, "stdout");
+ Log.i(TAG, stdout);
+ Log.i(TAG, "stderr");
+ Log.i(TAG, stderr);
+ if (res != 0) {
+ throw new RuntimeException(String.format("failed command: '%s'", cmd));
+ }
+ return stdout;
+ }
+
+ // Run the command and return the stdout split by lines.
+ private static String[] runShellCommandSplitLines(String cmd) throws IOException {
+ return runShellCommand(cmd).split("\n");
+ }
+
+ // Return the compiler filter of a package.
+ private static String getCompilerFilter(String pkg) throws IOException {
+ String cmd = String.format("dumpsys package %s", pkg);
+ String[] lines = runShellCommandSplitLines(cmd);
+ final String substr = "compilation_filter=";
+ for (String line : lines) {
+ int startIndex = line.indexOf(substr);
+ if (startIndex < 0) {
+ continue;
+ }
+ startIndex += substr.length();
+ int endIndex = line.indexOf(']', startIndex);
+ return line.substring(startIndex, endIndex);
+ }
+ throw new RuntimeException("Couldn't find compiler filter in dumpsys package");
+ }
+
+ // Return the number of bytes available in the data partition.
+ private static long getDataDirUsableSpace() {
+ return Environment.getDataDirectory().getUsableSpace();
+ }
+
+ // Fill up the storage until there are bytesRemaining number of bytes available in the data
+ // partition. Writes to the current package's data directory.
+ private void fillUpStorage(long bytesRemaining) throws IOException {
+ Log.i(TAG, String.format("Filling up storage with %d bytes remaining", bytesRemaining));
+ logSpaceRemaining();
+ long numBytesToAdd = getDataDirUsableSpace() - bytesRemaining;
+ String cmd = String.format("fallocate -l %d %s", numBytesToAdd, mBigFile.getAbsolutePath());
+ runShellCommand(cmd);
+ logSpaceRemaining();
+ }
+
+ // Fill up storage so that device is in low storage condition.
+ private void fillUpToLowStorage() throws IOException {
+ fillUpStorage((long) (getStorageLowBytes() * LOW_STORAGE_MULTIPLIER));
+ }
+
+ // TODO(aeubanks): figure out how to get scheduled bg-dexopt to run
+ private static void runBackgroundDexOpt() throws IOException {
+ runShellCommand("cmd package bg-dexopt-job " + PACKAGE_NAME);
+ }
+
+ // Set the time ahead of the last use time of the test app in days.
+ private static void setTimeFutureDays(long futureDays) {
+ setTimeFutureMillis(TimeUnit.DAYS.toMillis(futureDays));
+ }
+
+ // Set the time ahead of the last use time of the test app in milliseconds.
+ private static void setTimeFutureMillis(long futureMillis) {
+ long currentTime = System.currentTimeMillis();
+ setTime(currentTime + futureMillis);
+ }
+
+ private static void setTime(long time) {
+ AlarmManager am = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
+ am.setTime(time);
+ }
+
+ // Return the number of free bytes when the data partition is considered low on storage.
+ private static long getStorageLowBytes() {
+ StorageManager storageManager = (StorageManager) getContext().getSystemService(
+ Context.STORAGE_SERVICE);
+ return storageManager.getStorageLowBytes(Environment.getDataDirectory());
+ }
+
+ // Log the amount of space remaining in the data directory.
+ private static void logSpaceRemaining() throws IOException {
+ runShellCommand("df -h /data");
+ }
+
+ // Compile the given package with the given compiler filter.
+ private static void compilePackageWithFilter(String pkg, String filter) throws IOException {
+ runShellCommand(String.format("cmd package compile -f -m %s %s", filter, pkg));
+ }
+
+ // Test that background dexopt under normal conditions succeeds.
+ @Test
+ public void testBackgroundDexOpt() throws IOException {
+ // Set filter to quicken.
+ compilePackageWithFilter(PACKAGE_NAME, "verify");
+ Assert.assertEquals("verify", getCompilerFilter(PACKAGE_NAME));
+
+ runBackgroundDexOpt();
+
+ // Verify that bg-dexopt is successful.
+ Assert.assertEquals(BG_DEXOPT_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME));
+ }
+
+ // Test that background dexopt under low storage conditions upgrades used packages.
+ @Test
+ public void testBackgroundDexOptDowngradeSkipRecentlyUsedPackage() throws IOException {
+ // Should be less than DOWNGRADE_AFTER_DAYS.
+ long deltaDays = DOWNGRADE_AFTER_DAYS - 1;
+ try {
+ // Set time to future.
+ setTimeFutureDays(deltaDays);
+
+ // Set filter to quicken.
+ compilePackageWithFilter(PACKAGE_NAME, "quicken");
+ Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME));
+
+ // Fill up storage to trigger low storage threshold.
+ fillUpToLowStorage();
+
+ runBackgroundDexOpt();
+
+ // Verify that downgrade did not happen.
+ Assert.assertEquals(BG_DEXOPT_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME));
+ } finally {
+ // Reset time.
+ setTimeFutureDays(-deltaDays);
+ }
+ }
+
+ // Test that background dexopt under low storage conditions downgrades unused packages.
+ @Test
+ public void testBackgroundDexOptDowngradeSuccessful() throws IOException {
+ // Should be more than DOWNGRADE_AFTER_DAYS.
+ long deltaDays = DOWNGRADE_AFTER_DAYS + 1;
+ try {
+ // Set time to future.
+ setTimeFutureDays(deltaDays);
+
+ // Set filter to quicken.
+ compilePackageWithFilter(PACKAGE_NAME, "quicken");
+ Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME));
+
+ // Fill up storage to trigger low storage threshold.
+ fillUpToLowStorage();
+
+ runBackgroundDexOpt();
+
+ // Verify that downgrade is successful.
+ Assert.assertEquals(DOWNGRADE_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME));
+ } finally {
+ // Reset time.
+ setTimeFutureDays(-deltaDays);
+ }
+ }
+
+}
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk
index 527d1bbf..9e7f618 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk
@@ -24,7 +24,7 @@
LOCAL_SRC_FILES += $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := legacy-android-test
+LOCAL_JAVA_LIBRARIES := android.test.base
LOCAL_STATIC_JAVA_LIBRARIES := guava junit
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/tests/ServiceCrashTest/Android.mk b/tests/ServiceCrashTest/Android.mk
index d1f8456..f7b3452 100644
--- a/tests/ServiceCrashTest/Android.mk
+++ b/tests/ServiceCrashTest/Android.mk
@@ -9,7 +9,7 @@
LOCAL_PACKAGE_NAME := ServiceCrashTest
LOCAL_CERTIFICATE := platform
-LOCAL_JAVA_LIBRARIES := legacy-android-test
+LOCAL_JAVA_LIBRARIES := android.test.base
LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test
diff --git a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
index 6b9bb31..9174014 100644
--- a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
+++ b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
@@ -24,6 +24,7 @@
import android.util.Log;
import android.util.MergedConfiguration;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.IWindowSession;
import android.view.Surface;
import android.view.View;
@@ -103,7 +104,8 @@
WindowManagerGlobal.getWindowSession().relayout(window,
window.mSeq, mLayoutParams, -1, -1, View.VISIBLE, 0, mTmpRect,
mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect,
- new MergedConfiguration(), new Surface());
+ new DisplayCutout.ParcelableWrapper(), new MergedConfiguration(),
+ new Surface());
} catch (RemoteException e) {
e.printStackTrace();
}
diff --git a/tests/backup/Android.mk b/tests/backup/Android.mk
index 88794c2..202a699 100644
--- a/tests/backup/Android.mk
+++ b/tests/backup/Android.mk
@@ -20,7 +20,8 @@
LOCAL_SRC_FILES := \
backup_helper_test.cpp
-
+
+LOCAL_CFLAGS := -Wall -Werror
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := backup_helper_test
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
@@ -43,4 +44,3 @@
LOCAL_PROGUARD_ENABLED := disabled
include $(BUILD_PACKAGE)
-
diff --git a/tests/backup/backup_helper_test.cpp b/tests/backup/backup_helper_test.cpp
index b5f6ff5..457dcc4 100644
--- a/tests/backup/backup_helper_test.cpp
+++ b/tests/backup/backup_helper_test.cpp
@@ -118,7 +118,7 @@
#else
int
-main(int argc, char** argv)
+main(int, char**)
{
printf ("test_backup_helper built without the tests\n");
return 0;
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
index 677585c..1bd1af5 100644
--- a/tests/net/Android.mk
+++ b/tests/net/Android.mk
@@ -21,7 +21,9 @@
services.net
LOCAL_JAVA_LIBRARIES := \
- android.test.runner
+ android.test.runner \
+ android.test.base \
+ android.test.mock
LOCAL_PACKAGE_NAME := FrameworksNetTests
LOCAL_COMPATIBILITY_SUITE := device-tests
diff --git a/tests/net/java/android/net/IpSecAlgorithmTest.java b/tests/net/java/android/net/IpSecAlgorithmTest.java
new file mode 100644
index 0000000..6bdfdc6
--- /dev/null
+++ b/tests/net/java/android/net/IpSecAlgorithmTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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 android.net;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import java.util.Arrays;
+import java.util.Random;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit tests for {@link IpSecAlgorithm}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class IpSecAlgorithmTest {
+
+ private static final byte[] KEY_MATERIAL;
+
+ static {
+ KEY_MATERIAL = new byte[128];
+ new Random().nextBytes(KEY_MATERIAL);
+ };
+
+ @Test
+ public void testDefaultTruncLen() throws Exception {
+ IpSecAlgorithm explicit =
+ new IpSecAlgorithm(
+ IpSecAlgorithm.AUTH_HMAC_SHA256, Arrays.copyOf(KEY_MATERIAL, 256 / 8), 256);
+ IpSecAlgorithm implicit =
+ new IpSecAlgorithm(
+ IpSecAlgorithm.AUTH_HMAC_SHA256, Arrays.copyOf(KEY_MATERIAL, 256 / 8));
+ assertTrue(
+ "Default Truncation Length Incorrect, Explicit: "
+ + explicit
+ + "implicit: "
+ + implicit,
+ IpSecAlgorithm.equals(explicit, implicit));
+ }
+
+ @Test
+ public void testTruncLenValidation() throws Exception {
+ for (int truncLen : new int[] {256, 512}) {
+ new IpSecAlgorithm(
+ IpSecAlgorithm.AUTH_HMAC_SHA512,
+ Arrays.copyOf(KEY_MATERIAL, 512 / 8),
+ truncLen);
+ }
+
+ for (int truncLen : new int[] {255, 513}) {
+ try {
+ new IpSecAlgorithm(
+ IpSecAlgorithm.AUTH_HMAC_SHA512,
+ Arrays.copyOf(KEY_MATERIAL, 512 / 8),
+ truncLen);
+ fail("Invalid truncation length not validated");
+ } catch (IllegalArgumentException pass) {
+ }
+ }
+ }
+
+ @Test
+ public void testLenValidation() throws Exception {
+ for (int len : new int[] {128, 192, 256}) {
+ new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, Arrays.copyOf(KEY_MATERIAL, len / 8));
+ }
+ try {
+ new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, Arrays.copyOf(KEY_MATERIAL, 384 / 8));
+ fail("Invalid key length not validated");
+ } catch (IllegalArgumentException pass) {
+ }
+ }
+
+ @Test
+ public void testAlgoNameValidation() throws Exception {
+ try {
+ new IpSecAlgorithm("rot13", Arrays.copyOf(KEY_MATERIAL, 128 / 8));
+ fail("Invalid algorithm name not validated");
+ } catch (IllegalArgumentException pass) {
+ }
+ }
+
+ @Test
+ public void testParcelUnparcel() throws Exception {
+ IpSecAlgorithm init =
+ new IpSecAlgorithm(
+ IpSecAlgorithm.AUTH_HMAC_SHA512, Arrays.copyOf(KEY_MATERIAL, 512 / 8), 256);
+
+ Parcel p = Parcel.obtain();
+ p.setDataPosition(0);
+ init.writeToParcel(p, 0);
+
+ p.setDataPosition(0);
+ IpSecAlgorithm fin = IpSecAlgorithm.CREATOR.createFromParcel(p);
+ assertTrue("Parcel/Unparcel failed!", IpSecAlgorithm.equals(init, fin));
+ p.recycle();
+ }
+}
diff --git a/tests/net/java/android/net/IpSecConfigTest.java b/tests/net/java/android/net/IpSecConfigTest.java
index 1b4bef5..efc01f2a 100644
--- a/tests/net/java/android/net/IpSecConfigTest.java
+++ b/tests/net/java/android/net/IpSecConfigTest.java
@@ -71,7 +71,7 @@
c.setAuthentication(
IpSecTransform.DIRECTION_OUT,
new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_SHA1,
+ IpSecAlgorithm.AUTH_HMAC_MD5,
new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0}));
c.setSpiResourceId(IpSecTransform.DIRECTION_OUT, 1984);
c.setEncryption(
@@ -82,7 +82,7 @@
c.setAuthentication(
IpSecTransform.DIRECTION_IN,
new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_SHA1,
+ IpSecAlgorithm.AUTH_HMAC_MD5,
new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 1}));
c.setSpiResourceId(IpSecTransform.DIRECTION_IN, 99);
assertParcelingIsLossless(c);
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
index fcbb9da..558dbb6 100644
--- a/tests/net/java/android/net/MacAddressTest.java
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -21,7 +21,6 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
-import android.net.MacAddress.MacAddressType;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -37,11 +36,11 @@
static class AddrTypeTestCase {
byte[] addr;
- MacAddressType expected;
+ int expectedType;
- static AddrTypeTestCase of(MacAddressType expected, int... addr) {
+ static AddrTypeTestCase of(int expectedType, int... addr) {
AddrTypeTestCase t = new AddrTypeTestCase();
- t.expected = expected;
+ t.expectedType = expectedType;
t.addr = toByteArray(addr);
return t;
}
@@ -50,41 +49,73 @@
@Test
public void testMacAddrTypes() {
AddrTypeTestCase[] testcases = {
- AddrTypeTestCase.of(null),
- AddrTypeTestCase.of(null, 0),
- AddrTypeTestCase.of(null, 1, 2, 3, 4, 5),
- AddrTypeTestCase.of(null, 1, 2, 3, 4, 5, 6, 7),
- AddrTypeTestCase.of(MacAddressType.UNICAST, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0),
- AddrTypeTestCase.of(MacAddressType.BROADCAST, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
- AddrTypeTestCase.of(MacAddressType.MULTICAST, 1, 2, 3, 4, 5, 6),
- AddrTypeTestCase.of(MacAddressType.MULTICAST, 11, 22, 33, 44, 55, 66),
- AddrTypeTestCase.of(MacAddressType.MULTICAST, 33, 33, 0xaa, 0xbb, 0xcc, 0xdd)
+ AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN),
+ AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN, 0),
+ AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN, 1, 2, 3, 4, 5),
+ AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN, 1, 2, 3, 4, 5, 6, 7),
+ AddrTypeTestCase.of(MacAddress.TYPE_UNICAST, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0),
+ AddrTypeTestCase.of(MacAddress.TYPE_BROADCAST, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+ AddrTypeTestCase.of(MacAddress.TYPE_MULTICAST, 1, 2, 3, 4, 5, 6),
+ AddrTypeTestCase.of(MacAddress.TYPE_MULTICAST, 11, 22, 33, 44, 55, 66),
+ AddrTypeTestCase.of(MacAddress.TYPE_MULTICAST, 33, 33, 0xaa, 0xbb, 0xcc, 0xdd)
};
for (AddrTypeTestCase t : testcases) {
- MacAddressType got = MacAddress.macAddressType(t.addr);
+ int got = MacAddress.macAddressType(t.addr);
String msg = String.format("expected type of %s to be %s, but got %s",
- Arrays.toString(t.addr), t.expected, got);
- assertEquals(msg, t.expected, got);
+ Arrays.toString(t.addr), t.expectedType, got);
+ assertEquals(msg, t.expectedType, got);
- if (got != null) {
- assertEquals(got, new MacAddress(t.addr).addressType());
+ if (got != MacAddress.TYPE_UNKNOWN) {
+ assertEquals(got, MacAddress.fromBytes(t.addr).addressType());
}
}
}
@Test
+ public void testToSafeString() {
+ String[][] macs = {
+ {"07:00:d3:56:8a:c4", "07:00:d3:00:00:00"},
+ {"33:33:aa:bb:cc:dd", "33:33:aa:00:00:00"},
+ {"06:00:00:00:00:00", "06:00:00:00:00:00"},
+ {"07:00:d3:56:8a:c4", "07:00:d3:00:00:00"}
+ };
+
+ for (String[] pair : macs) {
+ String mac = pair[0];
+ String expected = pair[1];
+ assertEquals(expected, MacAddress.fromString(mac).toSafeString());
+ }
+ }
+
+ @Test
+ public void testHexPaddingWhenPrinting() {
+ String[] macs = {
+ "07:00:d3:56:8a:c4",
+ "33:33:aa:bb:cc:dd",
+ "06:00:00:00:00:00",
+ "07:00:d3:56:8a:c4"
+ };
+
+ for (String mac : macs) {
+ assertEquals(mac, MacAddress.fromString(mac).toString());
+ assertEquals(mac,
+ MacAddress.stringAddrFromByteAddr(MacAddress.byteAddrFromStringAddr(mac)));
+ }
+ }
+
+ @Test
public void testIsMulticastAddress() {
MacAddress[] multicastAddresses = {
MacAddress.BROADCAST_ADDRESS,
- new MacAddress("07:00:d3:56:8a:c4"),
- new MacAddress("33:33:aa:bb:cc:dd"),
+ MacAddress.fromString("07:00:d3:56:8a:c4"),
+ MacAddress.fromString("33:33:aa:bb:cc:dd"),
};
MacAddress[] unicastAddresses = {
MacAddress.ALL_ZEROS_ADDRESS,
- new MacAddress("00:01:44:55:66:77"),
- new MacAddress("08:00:22:33:44:55"),
- new MacAddress("06:00:00:00:00:00"),
+ MacAddress.fromString("00:01:44:55:66:77"),
+ MacAddress.fromString("08:00:22:33:44:55"),
+ MacAddress.fromString("06:00:00:00:00:00"),
};
for (MacAddress mac : multicastAddresses) {
@@ -100,13 +131,13 @@
@Test
public void testIsLocallyAssignedAddress() {
MacAddress[] localAddresses = {
- new MacAddress("06:00:00:00:00:00"),
- new MacAddress("07:00:d3:56:8a:c4"),
- new MacAddress("33:33:aa:bb:cc:dd"),
+ MacAddress.fromString("06:00:00:00:00:00"),
+ MacAddress.fromString("07:00:d3:56:8a:c4"),
+ MacAddress.fromString("33:33:aa:bb:cc:dd"),
};
MacAddress[] universalAddresses = {
- new MacAddress("00:01:44:55:66:77"),
- new MacAddress("08:00:22:33:44:55"),
+ MacAddress.fromString("00:01:44:55:66:77"),
+ MacAddress.fromString("08:00:22:33:44:55"),
};
for (MacAddress mac : localAddresses) {
@@ -123,13 +154,16 @@
public void testMacAddressConversions() {
final int iterations = 10000;
for (int i = 0; i < iterations; i++) {
- MacAddress mac = MacAddress.getRandomAddress();
+ MacAddress mac = MacAddress.createRandomUnicastAddress();
String stringRepr = mac.toString();
byte[] bytesRepr = mac.toByteArray();
- assertEquals(mac, new MacAddress(stringRepr));
- assertEquals(mac, new MacAddress(bytesRepr));
+ assertEquals(mac, MacAddress.fromString(stringRepr));
+ assertEquals(mac, MacAddress.fromBytes(bytesRepr));
+
+ assertEquals(mac, MacAddress.fromString(MacAddress.stringAddrFromByteAddr(bytesRepr)));
+ assertEquals(mac, MacAddress.fromBytes(MacAddress.byteAddrFromStringAddr(stringRepr)));
}
}
@@ -138,7 +172,7 @@
final int iterations = 1000;
final String expectedAndroidOui = "da:a1:19";
for (int i = 0; i < iterations; i++) {
- MacAddress mac = MacAddress.getRandomAddress();
+ MacAddress mac = MacAddress.createRandomUnicastAddress();
String stringRepr = mac.toString();
assertTrue(stringRepr + " expected to be a locally assigned address",
@@ -150,13 +184,14 @@
final Random r = new Random();
final String anotherOui = "24:5f:78";
final String expectedLocalOui = "26:5f:78";
- final MacAddress base = new MacAddress(anotherOui + ":0:0:0");
+ final MacAddress base = MacAddress.fromString(anotherOui + ":0:0:0");
for (int i = 0; i < iterations; i++) {
- MacAddress mac = MacAddress.getRandomAddress(base, r);
+ MacAddress mac = MacAddress.createRandomUnicastAddress(base, r);
String stringRepr = mac.toString();
assertTrue(stringRepr + " expected to be a locally assigned address",
mac.isLocallyAssigned());
+ assertEquals(MacAddress.TYPE_UNICAST, mac.addressType());
assertTrue(stringRepr + " expected to begin with " + expectedLocalOui,
stringRepr.startsWith(expectedLocalOui));
}
@@ -165,7 +200,6 @@
@Test
public void testConstructorInputValidation() {
String[] invalidStringAddresses = {
- null,
"",
"abcd",
"1:2:3:4:5",
@@ -175,14 +209,19 @@
for (String s : invalidStringAddresses) {
try {
- MacAddress mac = new MacAddress(s);
- fail("new MacAddress(" + s + ") should have failed, but returned " + mac);
+ MacAddress mac = MacAddress.fromString(s);
+ fail("MacAddress.fromString(" + s + ") should have failed, but returned " + mac);
} catch (IllegalArgumentException excepted) {
}
}
+ try {
+ MacAddress mac = MacAddress.fromString(null);
+ fail("MacAddress.fromString(null) should have failed, but returned " + mac);
+ } catch (NullPointerException excepted) {
+ }
+
byte[][] invalidBytesAddresses = {
- null,
{},
{1,2,3,4,5},
{1,2,3,4,5,6,7},
@@ -190,12 +229,18 @@
for (byte[] b : invalidBytesAddresses) {
try {
- MacAddress mac = new MacAddress(b);
- fail("new MacAddress(" + Arrays.toString(b)
+ MacAddress mac = MacAddress.fromBytes(b);
+ fail("MacAddress.fromBytes(" + Arrays.toString(b)
+ ") should have failed, but returned " + mac);
} catch (IllegalArgumentException excepted) {
}
}
+
+ try {
+ MacAddress mac = MacAddress.fromBytes(null);
+ fail("MacAddress.fromBytes(null) should have failed, but returned " + mac);
+ } catch (NullPointerException excepted) {
+ }
}
static byte[] toByteArray(int... in) {
diff --git a/tests/net/java/android/net/ip/IpManagerTest.java b/tests/net/java/android/net/ip/IpManagerTest.java
index 22d88fb..ebf121a 100644
--- a/tests/net/java/android/net/ip/IpManagerTest.java
+++ b/tests/net/java/android/net/ip/IpManagerTest.java
@@ -69,6 +69,8 @@
/**
* Tests for IpManager.
+ *
+ * TODO: Rename to IpClientTest.
*/
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -111,6 +113,10 @@
verify(mNMService, times(1)).registerObserver(arg.capture());
mObserver = arg.getValue();
reset(mNMService);
+ final LinkProperties emptyLp = new LinkProperties();
+ emptyLp.setInterfaceName(ifname);
+ verify(mCb, timeout(100)).onLinkPropertiesChange(eq(emptyLp));
+ reset(mCb);
return ipm;
}
diff --git a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
index f849689..54776db 100644
--- a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
+++ b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
@@ -18,10 +18,12 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.when;
import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.Looper;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -42,14 +44,18 @@
@Mock IpReachabilityMonitor.Callback mCallback;
@Mock IpReachabilityMonitor.Dependencies mDependencies;
@Mock SharedLog mLog;
+ Handler mHandler;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mLog.forSubComponent(anyString())).thenReturn(mLog);
+ mHandler = new Handler(Looper.getMainLooper());
}
IpReachabilityMonitor makeMonitor() {
- return new IpReachabilityMonitor("fake0", 1, mLog, mCallback, null, mDependencies);
+ return new IpReachabilityMonitor(
+ "fake0", 1, mHandler, mLog, mCallback, null, mDependencies);
}
@Test
diff --git a/tests/net/java/android/net/netlink/NetlinkSocketTest.java b/tests/net/java/android/net/netlink/NetlinkSocketTest.java
index bd36bac8..11be40b 100644
--- a/tests/net/java/android/net/netlink/NetlinkSocketTest.java
+++ b/tests/net/java/android/net/netlink/NetlinkSocketTest.java
@@ -16,6 +16,8 @@
package android.net.netlink;
+import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE;
+import static android.system.OsConstants.NETLINK_ROUTE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -28,10 +30,12 @@
import android.support.test.filters.SmallTest;
import android.system.ErrnoException;
import android.system.NetlinkSocketAddress;
-import android.system.OsConstants;
+import android.system.Os;
import android.util.Log;
+import libcore.io.IoUtils;
import java.io.InterruptedIOException;
+import java.io.FileDescriptor;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -46,29 +50,28 @@
@Test
public void testBasicWorkingGetNeighborsQuery() throws Exception {
- NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
- assertNotNull(s);
+ final FileDescriptor fd = NetlinkSocket.forProto(NETLINK_ROUTE);
+ assertNotNull(fd);
- s.connectToKernel();
+ NetlinkSocket.connectToKernel(fd);
- NetlinkSocketAddress localAddr = s.getLocalAddress();
+ final NetlinkSocketAddress localAddr = (NetlinkSocketAddress) Os.getsockname(fd);
assertNotNull(localAddr);
assertEquals(0, localAddr.getGroupsMask());
assertTrue(0 != localAddr.getPortId());
final int TEST_SEQNO = 5;
- final byte[] request = RtNetlinkNeighborMessage.newGetNeighborsRequest(TEST_SEQNO);
- assertNotNull(request);
+ final byte[] req = RtNetlinkNeighborMessage.newGetNeighborsRequest(TEST_SEQNO);
+ assertNotNull(req);
final long TIMEOUT = 500;
- assertTrue(s.sendMessage(request, 0, request.length, TIMEOUT));
+ assertEquals(req.length, NetlinkSocket.sendMessage(fd, req, 0, req.length, TIMEOUT));
int neighMessageCount = 0;
int doneMessageCount = 0;
while (doneMessageCount == 0) {
- ByteBuffer response = null;
- response = s.recvMessage(TIMEOUT);
+ ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT);
assertNotNull(response);
assertTrue(StructNlMsgHdr.STRUCT_SIZE <= response.limit());
assertEquals(0, response.position());
@@ -100,30 +103,6 @@
// TODO: make sure this test passes sanely in airplane mode.
assertTrue(neighMessageCount > 0);
- s.close();
- }
-
- @Test
- public void testRepeatedCloseCallsAreQuiet() throws Exception {
- // Create a working NetlinkSocket.
- NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
- assertNotNull(s);
- s.connectToKernel();
- NetlinkSocketAddress localAddr = s.getLocalAddress();
- assertNotNull(localAddr);
- assertEquals(0, localAddr.getGroupsMask());
- assertTrue(0 != localAddr.getPortId());
- // Close once.
- s.close();
- // Test that it is closed.
- boolean expectedErrorSeen = false;
- try {
- localAddr = s.getLocalAddress();
- } catch (ErrnoException e) {
- expectedErrorSeen = true;
- }
- assertTrue(expectedErrorSeen);
- // Close once more.
- s.close();
+ IoUtils.closeQuietly(fd);
}
}
diff --git a/tests/net/java/android/net/util/BlockingSocketReaderTest.java b/tests/net/java/android/net/util/PacketReaderTest.java
similarity index 91%
rename from tests/net/java/android/net/util/BlockingSocketReaderTest.java
rename to tests/net/java/android/net/util/PacketReaderTest.java
index 29dfa4c..dced743 100644
--- a/tests/net/java/android/net/util/BlockingSocketReaderTest.java
+++ b/tests/net/java/android/net/util/PacketReaderTest.java
@@ -16,7 +16,7 @@
package android.net.util;
-import static android.net.util.BlockingSocketReader.DEFAULT_RECV_BUF_SIZE;
+import static android.net.util.PacketReader.DEFAULT_RECV_BUF_SIZE;
import static android.system.OsConstants.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -53,13 +53,13 @@
import libcore.io.IoBridge;
/**
- * Tests for BlockingSocketReader.
+ * Tests for PacketReader.
*
* @hide
*/
@RunWith(AndroidJUnit4.class)
@SmallTest
-public class BlockingSocketReaderTest {
+public class PacketReaderTest {
static final InetAddress LOOPBACK6 = Inet6Address.getLoopbackAddress();
static final StructTimeval TIMEO = StructTimeval.fromMillis(500);
@@ -69,9 +69,9 @@
protected byte[] mLastRecvBuf;
protected boolean mStopped;
protected HandlerThread mHandlerThread;
- protected BlockingSocketReader mReceiver;
+ protected PacketReader mReceiver;
- class UdpLoopbackReader extends BlockingSocketReader {
+ class UdpLoopbackReader extends PacketReader {
public UdpLoopbackReader(Handler h) {
super(h);
}
@@ -121,7 +121,7 @@
mLastRecvBuf = null;
mStopped = false;
- mHandlerThread = new HandlerThread(BlockingSocketReaderTest.class.getSimpleName());
+ mHandlerThread = new HandlerThread(PacketReaderTest.class.getSimpleName());
mHandlerThread.start();
}
@@ -188,8 +188,8 @@
mReceiver = null;
}
- class NullBlockingSocketReader extends BlockingSocketReader {
- public NullBlockingSocketReader(Handler h, int recvbufsize) {
+ class NullPacketReader extends PacketReader {
+ public NullPacketReader(Handler h, int recvbufsize) {
super(h, recvbufsize);
}
@@ -202,7 +202,7 @@
final Handler h = mHandlerThread.getThreadHandler();
for (int i : new int[]{-1, 0, 1, DEFAULT_RECV_BUF_SIZE-1}) {
- final BlockingSocketReader b = new NullBlockingSocketReader(h, i);
+ final PacketReader b = new NullPacketReader(h, i);
assertEquals(DEFAULT_RECV_BUF_SIZE, b.recvBufSize());
}
}
diff --git a/tests/net/java/com/android/internal/util/RingBufferTest.java b/tests/net/java/com/android/internal/util/RingBufferTest.java
index 7a2344317..90a373a 100644
--- a/tests/net/java/com/android/internal/util/RingBufferTest.java
+++ b/tests/net/java/com/android/internal/util/RingBufferTest.java
@@ -17,6 +17,7 @@
package com.android.internal.util;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import android.support.test.filters.SmallTest;
@@ -129,6 +130,55 @@
assertArraysEqual(expected2, buffer.toArray());
}
+ @Test
+ public void testGetNextSlot() {
+ int capacity = 100;
+ RingBuffer<DummyClass1> buffer = new RingBuffer<>(DummyClass1.class, capacity);
+
+ final DummyClass1[] actual = new DummyClass1[capacity];
+ final DummyClass1[] expected = new DummyClass1[capacity];
+ for (int i = 0; i < capacity; ++i) {
+ final DummyClass1 obj = buffer.getNextSlot();
+ obj.x = capacity * i;
+ actual[i] = obj;
+ expected[i] = new DummyClass1();
+ expected[i].x = capacity * i;
+ }
+ assertArraysEqual(expected, buffer.toArray());
+
+ for (int i = 0; i < capacity; ++i) {
+ if (actual[i] != buffer.getNextSlot()) {
+ fail("getNextSlot() should re-use objects if available");
+ }
+ }
+
+ RingBuffer<DummyClass2> buffer2 = new RingBuffer<>(DummyClass2.class, capacity);
+ assertNull("getNextSlot() should return null if the object can't be initiated "
+ + "(No nullary constructor)", buffer2.getNextSlot());
+
+ RingBuffer<DummyClass3> buffer3 = new RingBuffer<>(DummyClass3.class, capacity);
+ assertNull("getNextSlot() should return null if the object can't be initiated "
+ + "(Inaccessible class)", buffer3.getNextSlot());
+ }
+
+ public static final class DummyClass1 {
+ int x;
+
+ public boolean equals(Object o) {
+ if (o instanceof DummyClass1) {
+ final DummyClass1 other = (DummyClass1) o;
+ return other.x == this.x;
+ }
+ return false;
+ }
+ }
+
+ public static final class DummyClass2 {
+ public DummyClass2(int x) {}
+ }
+
+ private static final class DummyClass3 {}
+
static <T> void assertArraysEqual(T[] expected, T[] got) {
if (expected.length != got.length) {
fail(Arrays.toString(expected) + " and " + Arrays.toString(got)
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index 8e579aa..0720886f 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -270,8 +270,8 @@
}
/**
- * This function checks if the number of encap UDP socket that one UID can reserve
- * has a reasonable limit.
+ * This function checks if the number of encap UDP socket that one UID can reserve has a
+ * reasonable limit.
*/
@Test
public void testSocketResourceTrackerLimitation() throws Exception {
@@ -287,9 +287,10 @@
openUdpEncapSockets.add(newUdpEncapSocket);
}
// Assert that the total sockets quota has a reasonable limit.
+ assertTrue("No UDP encap socket was open", !openUdpEncapSockets.isEmpty());
assertTrue(
- openUdpEncapSockets.size() > 0
- && openUdpEncapSockets.size() < MAX_NUM_ENCAP_SOCKETS);
+ "Number of open UDP encap sockets is out of bound",
+ openUdpEncapSockets.size() < MAX_NUM_ENCAP_SOCKETS);
// Try to reserve one more UDP encapsulation socket, and should fail.
IpSecUdpEncapResponse extraUdpEncapSocket =
@@ -297,7 +298,7 @@
assertNotNull(extraUdpEncapSocket);
assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, extraUdpEncapSocket.status);
- // Close one of the open UDP encapsulation scokets.
+ // Close one of the open UDP encapsulation sockets.
mIpSecService.closeUdpEncapsulationSocket(openUdpEncapSockets.get(0).resourceId);
openUdpEncapSockets.get(0).fileDescriptor.close();
openUdpEncapSockets.remove(0);
@@ -316,10 +317,9 @@
}
/**
- * This function checks if the number of SPI that one UID can reserve
- * has a reasonable limit.
- * This test does not test for both address families or duplicate SPIs because resource
- * tracking code does not depend on them.
+ * This function checks if the number of SPI that one UID can reserve has a reasonable limit.
+ * This test does not test for both address families or duplicate SPIs because resource tracking
+ * code does not depend on them.
*/
@Test
public void testSpiResourceTrackerLimitation() throws Exception {
diff --git a/tests/privapp-permissions/Android.mk b/tests/privapp-permissions/Android.mk
new file mode 100644
index 0000000..b001c8c
--- /dev/null
+++ b/tests/privapp-permissions/Android.mk
@@ -0,0 +1,31 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := PrivAppPermissionTest
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_MANIFEST_FILE := system/AndroidManifest.xml
+LOCAL_REQUIRED_MODULES := privapp-permissions-test.xml
+include $(BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := privapp-permissions-test.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
+LOCAL_SRC_FILES:= system/privapp-permissions-test.xml
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := VendorPrivAppPermissionTest
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_MANIFEST_FILE := vendor/AndroidManifest.xml
+LOCAL_VENDOR_MODULE := true
+LOCAL_REQUIRED_MODULES := vendorprivapp-permissions-test.xml
+include $(BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := vendorprivapp-permissions-test.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)/permissions
+LOCAL_SRC_FILES:= vendor/privapp-permissions-test.xml
+include $(BUILD_PREBUILT)
+
diff --git a/tests/privapp-permissions/system/AndroidManifest.xml b/tests/privapp-permissions/system/AndroidManifest.xml
new file mode 100644
index 0000000..2099e31
--- /dev/null
+++ b/tests/privapp-permissions/system/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.framework.permission.privapp.tests.system">
+
+ <!-- MANAGE_USB is signature|privileged -->
+ <uses-permission android:name="android.permission.MANAGE_USB"/>
+</manifest>
diff --git a/tests/privapp-permissions/system/privapp-permissions-test.xml b/tests/privapp-permissions/system/privapp-permissions-test.xml
new file mode 100644
index 0000000..a0cb6bc
--- /dev/null
+++ b/tests/privapp-permissions/system/privapp-permissions-test.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<permissions>
+ <privapp-permissions package="com.android.framework.permission.privapp.tests.system">
+ <permission name="android.permission.MANAGE_USB"/>
+ </privapp-permissions>
+</permissions>
diff --git a/tests/privapp-permissions/vendor/AndroidManifest.xml b/tests/privapp-permissions/vendor/AndroidManifest.xml
new file mode 100644
index 0000000..78dedc5
--- /dev/null
+++ b/tests/privapp-permissions/vendor/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.framework.permission.privapp.tests.vendor">
+
+ <!-- BIND_IMS_SERVICE is signature|privileged|vendorPrivileged -->
+ <uses-permission android:name="android.permission.BIND_IMS_SERVICE"/>
+ <!-- MANAGE_USB is signature|privileged and thus cannot be granted to this app -->
+ <uses-permission android:name="android.permission.MANAGE_USB"/>
+</manifest>
diff --git a/tests/privapp-permissions/vendor/privapp-permissions-test.xml b/tests/privapp-permissions/vendor/privapp-permissions-test.xml
new file mode 100644
index 0000000..51c588f
--- /dev/null
+++ b/tests/privapp-permissions/vendor/privapp-permissions-test.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<permissions>
+ <privapp-permissions package="com.android.framework.permission.privapp.tests.vendor">
+ <permission name="android.permission.BIND_IMS_SERVICE"/>
+ <permission name="android.permission.MANAGE_USB"/>
+ </privapp-permissions>
+</permissions>
diff --git a/tests/testables/Android.mk b/tests/testables/Android.mk
index 0e36981..7fcfc6e 100644
--- a/tests/testables/Android.mk
+++ b/tests/testables/Android.mk
@@ -25,10 +25,9 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
- mockito-target-minus-junit4 \
- legacy-android-test
+ mockito-target-minus-junit4
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.mock
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/testables/src/android/testing/TestableContext.java b/tests/testables/src/android/testing/TestableContext.java
index 498d517..ffe7219 100644
--- a/tests/testables/src/android/testing/TestableContext.java
+++ b/tests/testables/src/android/testing/TestableContext.java
@@ -25,6 +25,7 @@
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.os.UserHandle;
@@ -69,6 +70,7 @@
private LeakCheck.Tracker mService;
private LeakCheck.Tracker mComponent;
private TestableResources mTestableResources;
+ private TestablePermissions mTestablePermissions;
public TestableContext(Context base) {
this(base, null);
@@ -302,6 +304,159 @@
super.unregisterComponentCallbacks(callback);
}
+ public TestablePermissions getTestablePermissions() {
+ if (mTestablePermissions == null) {
+ mTestablePermissions = new TestablePermissions();
+ }
+ return mTestablePermissions;
+ }
+
+ @Override
+ public int checkCallingOrSelfPermission(String permission) {
+ if (mTestablePermissions != null && mTestablePermissions.wantsCall(permission)) {
+ return mTestablePermissions.check(permission);
+ }
+ return super.checkCallingOrSelfPermission(permission);
+ }
+
+ @Override
+ public int checkCallingPermission(String permission) {
+ if (mTestablePermissions != null && mTestablePermissions.wantsCall(permission)) {
+ return mTestablePermissions.check(permission);
+ }
+ return super.checkCallingPermission(permission);
+ }
+
+ @Override
+ public int checkPermission(String permission, int pid, int uid) {
+ if (mTestablePermissions != null && mTestablePermissions.wantsCall(permission)) {
+ return mTestablePermissions.check(permission);
+ }
+ return super.checkPermission(permission, pid, uid);
+ }
+
+ @Override
+ public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
+ if (mTestablePermissions != null && mTestablePermissions.wantsCall(permission)) {
+ return mTestablePermissions.check(permission);
+ }
+ return super.checkPermission(permission, pid, uid, callerToken);
+ }
+
+ @Override
+ public int checkSelfPermission(String permission) {
+ if (mTestablePermissions != null && mTestablePermissions.wantsCall(permission)) {
+ return mTestablePermissions.check(permission);
+ }
+ return super.checkSelfPermission(permission);
+ }
+
+ @Override
+ public void enforceCallingOrSelfPermission(String permission, String message) {
+ if (mTestablePermissions != null && mTestablePermissions.wantsCall(permission)) {
+ mTestablePermissions.enforce(permission);
+ } else {
+ super.enforceCallingOrSelfPermission(permission, message);
+ }
+ }
+
+ @Override
+ public void enforceCallingPermission(String permission, String message) {
+ if (mTestablePermissions != null && mTestablePermissions.wantsCall(permission)) {
+ mTestablePermissions.enforce(permission);
+ } else {
+ super.enforceCallingPermission(permission, message);
+ }
+ }
+
+ @Override
+ public void enforcePermission(String permission, int pid, int uid, String message) {
+ if (mTestablePermissions != null && mTestablePermissions.wantsCall(permission)) {
+ mTestablePermissions.enforce(permission);
+ } else {
+ super.enforcePermission(permission, pid, uid, message);
+ }
+ }
+
+ @Override
+ public int checkCallingOrSelfUriPermission(Uri uri, int modeFlags) {
+ if (mTestablePermissions != null && mTestablePermissions.wantsCall(uri)) {
+ return mTestablePermissions.check(uri, modeFlags);
+ }
+ return super.checkCallingOrSelfUriPermission(uri, modeFlags);
+ }
+
+ @Override
+ public int checkCallingUriPermission(Uri uri, int modeFlags) {
+ if (mTestablePermissions != null && mTestablePermissions.wantsCall(uri)) {
+ return mTestablePermissions.check(uri, modeFlags);
+ }
+ return super.checkCallingUriPermission(uri, modeFlags);
+ }
+
+ @Override
+ public void enforceCallingOrSelfUriPermission(Uri uri, int modeFlags, String message) {
+ if (mTestablePermissions != null && mTestablePermissions.wantsCall(uri)) {
+ mTestablePermissions.enforce(uri, modeFlags);
+ } else {
+ super.enforceCallingOrSelfUriPermission(uri, modeFlags, message);
+ }
+ }
+
+ @Override
+ public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
+ if (mTestablePermissions != null && mTestablePermissions.wantsCall(uri)) {
+ return mTestablePermissions.check(uri, modeFlags);
+ }
+ return super.checkUriPermission(uri, pid, uid, modeFlags);
+ }
+
+ @Override
+ public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, IBinder callerToken) {
+ if (mTestablePermissions != null && mTestablePermissions.wantsCall(uri)) {
+ return mTestablePermissions.check(uri, modeFlags);
+ }
+ return super.checkUriPermission(uri, pid, uid, modeFlags, callerToken);
+ }
+
+ @Override
+ public int checkUriPermission(Uri uri, String readPermission, String writePermission, int pid,
+ int uid, int modeFlags) {
+ if (mTestablePermissions != null && mTestablePermissions.wantsCall(uri)) {
+ return mTestablePermissions.check(uri, modeFlags);
+ }
+ return super.checkUriPermission(uri, readPermission, writePermission, pid, uid, modeFlags);
+ }
+
+ @Override
+ public void enforceCallingUriPermission(Uri uri, int modeFlags, String message) {
+ if (mTestablePermissions != null && mTestablePermissions.wantsCall(uri)) {
+ mTestablePermissions.enforce(uri, modeFlags);
+ } else {
+ super.enforceCallingUriPermission(uri, modeFlags, message);
+ }
+ }
+
+ @Override
+ public void enforceUriPermission(Uri uri, int pid, int uid, int modeFlags, String message) {
+ if (mTestablePermissions != null && mTestablePermissions.wantsCall(uri)) {
+ mTestablePermissions.enforce(uri, modeFlags);
+ } else {
+ super.enforceUriPermission(uri, pid, uid, modeFlags, message);
+ }
+ }
+
+ @Override
+ public void enforceUriPermission(Uri uri, String readPermission, String writePermission,
+ int pid, int uid, int modeFlags, String message) {
+ if (mTestablePermissions != null && mTestablePermissions.wantsCall(uri)) {
+ mTestablePermissions.enforce(uri, modeFlags);
+ } else {
+ super.enforceUriPermission(uri, readPermission, writePermission, pid, uid, modeFlags,
+ message);
+ }
+ }
+
@Override
public Statement apply(Statement base, Description description) {
return new TestWatcher() {
diff --git a/tests/testables/src/android/testing/TestablePermissions.java b/tests/testables/src/android/testing/TestablePermissions.java
new file mode 100644
index 0000000..4f009e4
--- /dev/null
+++ b/tests/testables/src/android/testing/TestablePermissions.java
@@ -0,0 +1,80 @@
+/*
+ * 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 android.testing;
+
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.util.ArrayMap;
+
+/**
+ * Simple class for simulating basic permission states for tests.
+ *
+ * All enforce* and check* calls on TestableContext are considered the same
+ * and routed through the same check here. If more fine-grained control is
+ * required, then either a sub-class or spy on TestableContext is recommended.
+ */
+public class TestablePermissions {
+
+ private final ArrayMap<String, Integer> mPermissions = new ArrayMap<>();
+ private final ArrayMap<Uri, Integer> mUris = new ArrayMap<>();
+
+ /**
+ * Sets the return value for checkPermission* calls on TestableContext
+ * for a specific permission value. For all enforcePermission* calls
+ * they will throw a security exception if value != PERMISSION_GRANTED.
+ */
+ public void setPermission(String permission, int value) {
+ mPermissions.put(permission, value);
+ }
+
+ /**
+ * Sets the return value for checkUriPermission* calls on TestableContext
+ * for a specific permission value. For all enforceUriPermission* calls
+ * they will throw a security exception if value != PERMISSION_GRANTED.
+ */
+ public void setPermission(Uri uri, int value) {
+ // TODO: Support modeFlags
+ mUris.put(uri, value);
+ }
+
+ boolean wantsCall(String permission) {
+ return mPermissions.containsKey(permission);
+ }
+
+ boolean wantsCall(Uri uri) {
+ return mUris.containsKey(uri);
+ }
+
+ int check(String permission) {
+ return mPermissions.get(permission);
+ }
+
+ int check(Uri uri, int modeFlags) {
+ // TODO: Support modeFlags
+ return mUris.get(uri);
+ }
+
+ public void enforce(String permission) {
+ if (check(permission) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException();
+ }
+ }
+
+ public void enforce(Uri uri, int modeFlags) {
+ if (check(uri, modeFlags) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException();
+ }
+ }
+}
diff --git a/tests/testables/src/android/testing/TestableResources.java b/tests/testables/src/android/testing/TestableResources.java
index a2fa95d..c60f07d 100644
--- a/tests/testables/src/android/testing/TestableResources.java
+++ b/tests/testables/src/android/testing/TestableResources.java
@@ -39,7 +39,8 @@
private final Resources mResources;
private final SparseArray<Object> mOverrides = new SparseArray<>();
- TestableResources(Resources realResources) {
+ /** Creates a TestableResources instance that calls through to the given real Resources. */
+ public TestableResources(Resources realResources) {
mResources = mock(Resources.class, withSettings()
.spiedInstance(realResources)
.defaultAnswer(this::answer));
diff --git a/tests/testables/tests/src/android/testing/TestablePermissionsTest.java b/tests/testables/tests/src/android/testing/TestablePermissionsTest.java
new file mode 100644
index 0000000..c56146e
--- /dev/null
+++ b/tests/testables/tests/src/android/testing/TestablePermissionsTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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 android.testing;
+
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import static org.junit.Assert.assertEquals;
+
+import android.Manifest.permission;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.testing.TestableLooper.RunWithLooper;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class TestablePermissionsTest {
+
+ private static final Uri URI_1 = Uri.parse("content://my.authority/path1");
+ private static final Uri URI_2 = Uri.parse("content://my.authority/path2");
+
+ @Rule
+ public TestableContext mContext = new TestableContext(InstrumentationRegistry.getContext());
+
+ @Test
+ public void testCheck() {
+ mContext.getTestablePermissions().setPermission(permission.INTERACT_ACROSS_USERS,
+ PERMISSION_GRANTED);
+ mContext.getTestablePermissions().setPermission(permission.INTERACT_ACROSS_USERS_FULL,
+ PERMISSION_DENIED);
+ assertEquals(PERMISSION_GRANTED,
+ mContext.checkPermission(permission.INTERACT_ACROSS_USERS, 0, 0));
+ assertEquals(PERMISSION_DENIED,
+ mContext.checkPermission(permission.INTERACT_ACROSS_USERS_FULL, 0, 0));
+ }
+
+ @Test
+ public void testCheckUri() {
+ mContext.getTestablePermissions().setPermission(URI_1, PERMISSION_GRANTED);
+ mContext.getTestablePermissions().setPermission(URI_2, PERMISSION_DENIED);
+
+ assertEquals(PERMISSION_GRANTED, mContext.checkUriPermission(URI_1, 0, 0, 0));
+ assertEquals(PERMISSION_DENIED, mContext.checkUriPermission(URI_2, 0, 0, 0));
+ }
+
+ @Test
+ public void testEnforceNoException() {
+ mContext.getTestablePermissions().setPermission(permission.INTERACT_ACROSS_USERS,
+ PERMISSION_GRANTED);
+ mContext.enforceCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS, "");
+ }
+
+ @Test(expected = SecurityException.class)
+ public void testEnforceWithException() {
+ mContext.getTestablePermissions().setPermission(permission.INTERACT_ACROSS_USERS,
+ PERMISSION_DENIED);
+ mContext.enforceCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS, "");
+ }
+
+ @Test
+ public void testEnforceUriNoException() {
+ mContext.getTestablePermissions().setPermission(URI_1, PERMISSION_GRANTED);
+ mContext.enforceUriPermission(URI_1, 0, 0, 0, "");
+ }
+
+ @Test(expected = SecurityException.class)
+ public void testEnforceUriWithException() {
+ mContext.getTestablePermissions().setPermission(URI_1, PERMISSION_DENIED);
+ mContext.enforceUriPermission(URI_1, 0, 0, 0, "");
+ }
+
+}
\ No newline at end of file
diff --git a/tests/utils/testutils/Android.mk b/tests/utils/testutils/Android.mk
index 43d1e37..543c652 100644
--- a/tests/utils/testutils/Android.mk
+++ b/tests/utils/testutils/Android.mk
@@ -25,9 +25,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
- legacy-android-test \
mockito-target-minus-junit4
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index a93ee2e..deb9cc0 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -68,6 +68,7 @@
mSingleCrunchInputFile(NULL), mSingleCrunchOutputFile(NULL),
mBuildSharedLibrary(false),
mBuildAppAsSharedLibrary(false),
+ mCompileSdkVersion(0),
mArgc(0), mArgv(NULL)
{}
~Bundle(void) {}
@@ -123,6 +124,10 @@
void setErrorOnFailedInsert(bool val) { mErrorOnFailedInsert = val; }
bool getErrorOnMissingConfigEntry() { return mErrorOnMissingConfigEntry; }
void setErrorOnMissingConfigEntry(bool val) { mErrorOnMissingConfigEntry = val; }
+ const android::String8& getCompileSdkVersionCodename() { return mCompileSdkVersionCodename; }
+ void setCompileSdkVersionCodename(const android::String8& codename) { mCompileSdkVersionCodename = codename; }
+ int getCompileSdkVersion() { return mCompileSdkVersion; }
+ void setCompileSdkVersion(int version) { mCompileSdkVersion = version; }
const android::String8& getPlatformBuildVersionCode() { return mPlatformVersionCode; }
void setPlatformBuildVersionCode(const android::String8& code) { mPlatformVersionCode = code; }
const android::String8& getPlatformBuildVersionName() { return mPlatformVersionName; }
@@ -344,6 +349,8 @@
const char* mSingleCrunchOutputFile;
bool mBuildSharedLibrary;
bool mBuildAppAsSharedLibrary;
+ int mCompileSdkVersion;
+ android::String8 mCompileSdkVersionCodename;
android::String8 mPlatformVersionCode;
android::String8 mPlatformVersionName;
android::String8 mPrivateSymbolsPackage;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index cb87737..05375b0 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -293,6 +293,8 @@
ISGAME_ATTR = 0x10103f4,
REQUIRED_FEATURE_ATTR = 0x1010557,
REQUIRED_NOT_FEATURE_ATTR = 0x1010558,
+ COMPILE_SDK_VERSION_ATTR = 0x01010572, // NOT FINALIZED
+ COMPILE_SDK_VERSION_CODENAME_ATTR = 0x01010573, // NOT FINALIZED
};
String8 getComponentName(String8 &pkgName, String8 &componentName) {
@@ -1247,9 +1249,37 @@
splitName.string()).string());
}
- String8 platformVersionName = AaptXml::getAttribute(tree, NULL,
+ String8 platformBuildVersionName = AaptXml::getAttribute(tree, NULL,
"platformBuildVersionName");
- printf(" platformBuildVersionName='%s'", platformVersionName.string());
+ if (platformBuildVersionName != "") {
+ printf(" platformBuildVersionName='%s'", platformBuildVersionName.string());
+ }
+
+ String8 platformBuildVersionCode = AaptXml::getAttribute(tree, NULL,
+ "platformBuildVersionCode");
+ if (platformBuildVersionCode != "") {
+ printf(" platformBuildVersionCode='%s'", platformBuildVersionCode.string());
+ }
+
+ int32_t compileSdkVersion = AaptXml::getIntegerAttribute(tree,
+ COMPILE_SDK_VERSION_ATTR, &error);
+ if (error != "") {
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:compileSdkVersion' attribute: %s",
+ error.string());
+ goto bail;
+ }
+ if (compileSdkVersion > 0) {
+ printf(" compileSdkVersion='%d'", compileSdkVersion);
+ }
+
+ String8 compileSdkVersionCodename = AaptXml::getResolvedAttribute(res, tree,
+ COMPILE_SDK_VERSION_CODENAME_ATTR, &error);
+ if (compileSdkVersionCodename != "") {
+ printf(" compileSdkVersionCodename='%s'", ResTable::normalizeForOutput(
+ compileSdkVersionCodename.string()).string());
+ }
+
printf("\n");
int32_t installLocation = AaptXml::getResolvedIntegerAttribute(res, tree,
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index bd2b2a36..ab6dced 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -918,6 +918,22 @@
}
}
+
+ if (bundle->getCompileSdkVersion() != 0) {
+ if (!addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "compileSdkVersion",
+ String8::format("%d", bundle->getCompileSdkVersion()),
+ errorOnFailedInsert, true)) {
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ if (bundle->getCompileSdkVersionCodename() != "") {
+ if (!addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "compileSdkVersionCodename",
+ bundle->getCompileSdkVersionCodename(), errorOnFailedInsert, true)) {
+ return UNKNOWN_ERROR;
+ }
+ }
+
if (bundle->getPlatformBuildVersionCode() != "") {
if (!addTagAttribute(root, "", "platformBuildVersionCode",
bundle->getPlatformBuildVersionCode(), errorOnFailedInsert, true)) {
@@ -1052,7 +1068,12 @@
VERSION_NAME_ATTR = 0x0101021c,
};
-static ssize_t extractPlatformBuildVersion(ResXMLTree& tree, Bundle* bundle) {
+static ssize_t extractPlatformBuildVersion(const ResTable& table, ResXMLTree& tree, Bundle* bundle) {
+ // First check if we should be recording the compileSdkVersion* attributes.
+ static const String16 compileSdkVersionName("android:attr/compileSdkVersion");
+ const bool useCompileSdkVersion = table.identifierForName(compileSdkVersionName.string(),
+ compileSdkVersionName.size()) != 0u;
+
size_t len;
ResXMLTree::event_code_t code;
while ((code = tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
@@ -1082,6 +1103,10 @@
bundle->setPlatformBuildVersionCode(String8::format("%d", versionCode));
}
+ if (useCompileSdkVersion && versionCode >= 0 && bundle->getCompileSdkVersion() == 0) {
+ bundle->setCompileSdkVersion(versionCode);
+ }
+
String8 versionName = AaptXml::getAttribute(tree, VERSION_NAME_ATTR, &error);
if (error != "") {
fprintf(stderr, "ERROR: failed to get platform version name\n");
@@ -1091,6 +1116,11 @@
if (versionName != "" && bundle->getPlatformBuildVersionName() == "") {
bundle->setPlatformBuildVersionName(versionName);
}
+
+ if (useCompileSdkVersion && versionName != ""
+ && bundle->getCompileSdkVersionCodename() == "") {
+ bundle->setCompileSdkVersionCodename(versionName);
+ }
return NO_ERROR;
}
@@ -1121,7 +1151,7 @@
fprintf(stderr, "ERROR: Platform AndroidManifest.xml is corrupt\n");
result = UNKNOWN_ERROR;
} else {
- result = extractPlatformBuildVersion(tree, bundle);
+ result = extractPlatformBuildVersion(assets.getResources(true), tree, bundle);
}
}
@@ -1707,7 +1737,9 @@
// extract them from the platform APK.
if (packageType != ResourceTable::System &&
(bundle->getPlatformBuildVersionCode() == "" ||
- bundle->getPlatformBuildVersionName() == "")) {
+ bundle->getPlatformBuildVersionName() == "" ||
+ bundle->getCompileSdkVersion() == 0 ||
+ bundle->getCompileSdkVersionCodename() == "")) {
err = extractPlatformBuildVersion(assets->getAssetManager(), bundle);
if (err != NO_ERROR) {
return UNKNOWN_ERROR;
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index e0c9d1c..c9987b8 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -1,7 +1,11 @@
+LOCAL_PATH := $(call my-dir)
+
include $(CLEAR_VARS)
+# Target for running host unit tests on post/pre-submit.
.PHONY: aapt2_run_host_unit_tests
aapt2_run_host_unit_tests: PRIVATE_GTEST_OPTIONS := --gtest_output=xml:$(DIST_DIR)/gtest/aapt2_host_unit_tests_result.xml
aapt2_run_host_unit_tests: $(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests
-$(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests $(PRIVATE_GTEST_OPTIONS) > /dev/null 2>&1
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index 5981401..33b5a8b 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -43,13 +43,16 @@
return {};
}
- if (apk->FindFile("resources.arsc") != nullptr) {
- return LoadBinaryApkFromFileCollection(source, std::move(apk), diag);
- } else if (apk->FindFile("resources.pb") != nullptr) {
- return LoadProtoApkFromFileCollection(source, std::move(apk), diag);
+ ApkFormat apkFormat = DetermineApkFormat(apk.get());
+ switch (apkFormat) {
+ case ApkFormat::kBinary:
+ return LoadBinaryApkFromFileCollection(source, std::move(apk), diag);
+ case ApkFormat::kProto:
+ return LoadProtoApkFromFileCollection(source, std::move(apk), diag);
+ default:
+ diag->Error(DiagMessage(path) << "could not identify format of APK");
+ return {};
}
- diag->Error(DiagMessage(path) << "no resource table found");
- return {};
}
std::unique_ptr<LoadedApk> LoadedApk::LoadProtoApkFromFileCollection(
@@ -243,4 +246,41 @@
return true;
}
+ApkFormat LoadedApk::DetermineApkFormat(io::IFileCollection* apk) {
+ if (apk->FindFile("resources.arsc") != nullptr) {
+ return ApkFormat::kBinary;
+ } else if (apk->FindFile("resources.pb") != nullptr) {
+ return ApkFormat::kProto;
+ } else {
+ // If the resource table is not present, attempt to read the manifest.
+ io::IFile* manifest_file = apk->FindFile(kAndroidManifestPath);
+ if (manifest_file == nullptr) {
+ return ApkFormat::kUnknown;
+ }
+
+ // First try in proto format.
+ std::unique_ptr<io::InputStream> manifest_in = manifest_file->OpenInputStream();
+ if (manifest_in != nullptr) {
+ pb::XmlNode pb_node;
+ io::ZeroCopyInputAdaptor manifest_adaptor(manifest_in.get());
+ if (pb_node.ParseFromZeroCopyStream(&manifest_adaptor)) {
+ return ApkFormat::kProto;
+ }
+ }
+
+ // If it didn't work, try in binary format.
+ std::unique_ptr<io::IData> manifest_data = manifest_file->OpenAsData();
+ if (manifest_data != nullptr) {
+ std::string error;
+ std::unique_ptr<xml::XmlResource> manifest =
+ xml::Inflate(manifest_data->data(), manifest_data->size(), &error);
+ if (manifest != nullptr) {
+ return ApkFormat::kBinary;
+ }
+ }
+
+ return ApkFormat::kUnknown;
+ }
+}
+
} // namespace aapt
diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h
index ef97de3..6d2257f 100644
--- a/tools/aapt2/LoadedApk.h
+++ b/tools/aapt2/LoadedApk.h
@@ -33,6 +33,12 @@
constexpr static const char kProtoResourceTablePath[] = "resources.pb";
constexpr static const char kAndroidManifestPath[] = "AndroidManifest.xml";
+enum ApkFormat {
+ kUnknown,
+ kBinary,
+ kProto,
+};
+
// Info about an APK loaded in memory.
class LoadedApk {
public:
@@ -104,6 +110,8 @@
std::unique_ptr<io::IFileCollection> apk_;
std::unique_ptr<ResourceTable> table_;
std::unique_ptr<xml::XmlResource> manifest_;
+
+ static ApkFormat DetermineApkFormat(io::IFileCollection* apk);
};
} // namespace aapt
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 24187d9..02ac86c 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -707,7 +707,9 @@
std::unique_ptr<FileReference> file_ref =
util::make_unique<FileReference>(dst_pool->MakeRef(
str, StringPool::Context(StringPool::Context::kHighPriority, config)));
- if (util::EndsWith(*file_ref->path, ".xml")) {
+ if (type == ResourceType::kRaw) {
+ file_ref->type = ResourceFile::Type::kUnknown;
+ } else if (util::EndsWith(*file_ref->path, ".xml")) {
file_ref->type = ResourceFile::Type::kBinaryXml;
} else if (util::EndsWith(*file_ref->path, ".png")) {
file_ref->type = ResourceFile::Type::kPng;
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index e94c0b4..13dd93e 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -15,6 +15,7 @@
*/
#include <sys/stat.h>
+#include <cinttypes>
#include <queue>
#include <unordered_map>
@@ -36,6 +37,7 @@
#include "ValueVisitor.h"
#include "cmd/Util.h"
#include "compile/IdAssigner.h"
+#include "compile/XmlIdCollector.h"
#include "filter/ConfigFilter.h"
#include "format/Archive.h"
#include "format/Container.h"
@@ -724,6 +726,30 @@
return true;
}
+static int32_t FindFrameworkAssetManagerCookie(const android::AssetManager& assets) {
+ using namespace android;
+
+ // Find the system package (0x01). AAPT always generates attributes with the type 0x01, so
+ // we're looking for the first attribute resource in the system package.
+ const ResTable& table = assets.getResources(true);
+ Res_value val;
+ ssize_t idx = table.getResource(0x01010000, &val, true);
+ if (idx != NO_ERROR) {
+ // Try as a bag.
+ const ResTable::bag_entry* entry;
+ ssize_t cnt = table.lockBag(0x01010000, &entry);
+ if (cnt >= 0) {
+ idx = entry->stringBlock;
+ }
+ table.unlockBag(entry);
+ }
+
+ if (idx < 0) {
+ return 0;
+ }
+ return table.getTableCookie(idx);
+}
+
class LinkCommand {
public:
LinkCommand(LinkContext* context, const LinkOptions& options)
@@ -733,7 +759,65 @@
file_collection_(util::make_unique<io::FileCollection>()) {
}
+ void ExtractCompileSdkVersions(android::AssetManager* assets) {
+ using namespace android;
+
+ int32_t cookie = FindFrameworkAssetManagerCookie(*assets);
+ if (cookie == 0) {
+ // No Framework assets loaded. Not a failure.
+ return;
+ }
+
+ std::unique_ptr<Asset> manifest(
+ assets->openNonAsset(cookie, kAndroidManifestPath, Asset::AccessMode::ACCESS_BUFFER));
+ if (manifest == nullptr) {
+ // No errors.
+ return;
+ }
+
+ std::string error;
+ std::unique_ptr<xml::XmlResource> manifest_xml =
+ xml::Inflate(manifest->getBuffer(true /*wordAligned*/), manifest->getLength(), &error);
+ if (manifest_xml == nullptr) {
+ // No errors.
+ return;
+ }
+
+ xml::Attribute* attr = manifest_xml->root->FindAttribute(xml::kSchemaAndroid, "versionCode");
+ if (attr != nullptr) {
+ Maybe<std::string>& compile_sdk_version = options_.manifest_fixer_options.compile_sdk_version;
+ if (BinaryPrimitive* prim = ValueCast<BinaryPrimitive>(attr->compiled_value.get())) {
+ switch (prim->value.dataType) {
+ case Res_value::TYPE_INT_DEC:
+ compile_sdk_version = StringPrintf("%" PRId32, static_cast<int32_t>(prim->value.data));
+ break;
+ case Res_value::TYPE_INT_HEX:
+ compile_sdk_version = StringPrintf("%" PRIx32, prim->value.data);
+ break;
+ default:
+ break;
+ }
+ } else if (String* str = ValueCast<String>(attr->compiled_value.get())) {
+ compile_sdk_version = *str->value;
+ } else {
+ compile_sdk_version = attr->value;
+ }
+ }
+
+ attr = manifest_xml->root->FindAttribute(xml::kSchemaAndroid, "versionName");
+ if (attr != nullptr) {
+ Maybe<std::string>& compile_sdk_version_codename =
+ options_.manifest_fixer_options.compile_sdk_version_codename;
+ if (String* str = ValueCast<String>(attr->compiled_value.get())) {
+ compile_sdk_version_codename = *str->value;
+ } else {
+ compile_sdk_version_codename = attr->value;
+ }
+ }
+ }
+
// Creates a SymbolTable that loads symbols from the various APKs.
+ // Pre-condition: context_->GetCompilationPackage() needs to be set.
bool LoadSymbolsFromIncludePaths() {
auto asset_source = util::make_unique<AssetManagerSymbolSource>();
for (const std::string& path : options_.include_paths) {
@@ -801,6 +885,17 @@
} else if (entry.first == kAppPackageId) {
// Capture the included base feature package.
included_feature_base_ = entry.second;
+ } else if (entry.first == kFrameworkPackageId) {
+ // Try to embed which version of the framework we're compiling against.
+ // First check if we should use compileSdkVersion at all. Otherwise compilation may fail
+ // when linking our synthesized 'android:compileSdkVersion' attribute.
+ std::unique_ptr<SymbolTable::Symbol> symbol = asset_source->FindByName(
+ ResourceName("android", ResourceType::kAttr, "compileSdkVersion"));
+ if (symbol != nullptr && symbol->is_public) {
+ // The symbol is present and public, extract the android:versionName and
+ // android:versionCode from the framework AndroidManifest.xml.
+ ExtractCompileSdkVersions(asset_source->GetAssetManager());
+ }
}
}
@@ -1235,19 +1330,10 @@
return true;
}
- bool MergeCompiledFile(const ResourceFile& compiled_file, io::IFile* file, bool override) {
- if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage()
- << "merging '" << compiled_file.name
- << "' from compiled file " << compiled_file.source);
- }
-
- if (!table_merger_->MergeFile(compiled_file, override, file)) {
- return false;
- }
-
+ bool MergeExportedSymbols(const Source& source,
+ const std::vector<SourcedResourceName>& exported_symbols) {
// Add the exports of this file to the table.
- for (const SourcedResourceName& exported_symbol : compiled_file.exported_symbols) {
+ for (const SourcedResourceName& exported_symbol : exported_symbols) {
ResourceName res_name = exported_symbol.name;
if (res_name.package.empty()) {
res_name.package = context_->GetCompilationPackage();
@@ -1259,7 +1345,7 @@
}
std::unique_ptr<Id> id = util::make_unique<Id>();
- id->SetSource(compiled_file.source.WithLine(exported_symbol.line));
+ id->SetSource(source.WithLine(exported_symbol.line));
bool result = final_table_.AddResourceAllowMangled(
res_name, ConfigDescription::DefaultConfig(), std::string(), std::move(id),
context_->GetDiagnostics());
@@ -1270,6 +1356,19 @@
return true;
}
+ bool MergeCompiledFile(const ResourceFile& compiled_file, io::IFile* file, bool override) {
+ if (context_->IsVerbose()) {
+ context_->GetDiagnostics()->Note(DiagMessage()
+ << "merging '" << compiled_file.name
+ << "' from compiled file " << compiled_file.source);
+ }
+
+ if (!table_merger_->MergeFile(compiled_file, override, file)) {
+ return false;
+ }
+ return MergeExportedSymbols(compiled_file.source, compiled_file.exported_symbols);
+ }
+
// Takes a path to load as a ZIP file and merges the files within into the master ResourceTable.
// If override is true, conflicting resources are allowed to override each other, in order of last
// seen.
@@ -1530,6 +1629,12 @@
context_->SetCompilationPackage(app_info.package);
}
+ // Now that the compilation package is set, load the dependencies. This will also extract
+ // the Android framework's versionCode and versionName, if they exist.
+ if (!LoadSymbolsFromIncludePaths()) {
+ return 1;
+ }
+
ManifestFixer manifest_fixer(options_.manifest_fixer_options);
if (!manifest_fixer.Consume(context_, manifest_xml.get())) {
return 1;
@@ -1558,10 +1663,6 @@
}
}
- if (!LoadSymbolsFromIncludePaths()) {
- return 1;
- }
-
TableMergerOptions table_merger_options;
table_merger_options.auto_add_overlay = options_.auto_add_overlay;
table_merger_ = util::make_unique<TableMerger>(context_, &final_table_, table_merger_options);
@@ -1573,6 +1674,19 @@
context_->GetPackageId()));
}
+ // Extract symbols from AndroidManifest.xml, since this isn't merged like the other XML files
+ // in res/**/*.
+ {
+ XmlIdCollector collector;
+ if (!collector.Consume(context_, manifest_xml.get())) {
+ return false;
+ }
+
+ if (!MergeExportedSymbols(manifest_xml->file.source, manifest_xml->file.exported_symbols)) {
+ return false;
+ }
+ }
+
for (const std::string& input : input_files) {
if (!MergePath(input, false)) {
context_->GetDiagnostics()->Error(DiagMessage() << "failed parsing input");
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 2bf91a5..1bdb762 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -17,6 +17,7 @@
#include <memory>
#include <vector>
+#include "android-base/file.h"
#include "android-base/stringprintf.h"
#include "androidfw/ResourceTypes.h"
@@ -47,6 +48,7 @@
using ::aapt::configuration::PostProcessingConfiguration;
using ::android::ResTable_config;
using ::android::StringPiece;
+using ::android::base::ReadFileToString;
using ::android::base::StringAppendF;
using ::android::base::StringPrintf;
@@ -73,6 +75,10 @@
TableFlattenerOptions table_flattener_options;
Maybe<PostProcessingConfiguration> configuration;
+
+ // Set of artifacts to keep when generating multi-APK splits. If the list is empty, all artifacts
+ // are kept and will be written as output.
+ std::unordered_set<std::string> kept_artifacts;
};
class OptimizeContext : public IAaptContext {
@@ -195,9 +201,12 @@
if (options_.configuration && options_.output_dir) {
MultiApkGenerator generator{apk.get(), context_};
- MultiApkGeneratorOptions generator_options = {options_.output_dir.value(),
- options_.configuration.value(),
- options_.table_flattener_options};
+ MultiApkGeneratorOptions generator_options = {
+ options_.output_dir.value(),
+ options_.configuration.value(),
+ options_.table_flattener_options,
+ options_.kept_artifacts,
+ };
if (!generator.FromBaseApk(generator_options)) {
return 1;
}
@@ -279,6 +288,20 @@
OptimizeContext* context_;
};
+bool ExtractWhitelistFromConfig(const std::string& path, OptimizeContext* context,
+ OptimizeOptions* options) {
+ std::string contents;
+ if (!ReadFileToString(path, &contents, true)) {
+ context->GetDiagnostics()->Error(DiagMessage()
+ << "failed to parse whitelist from config file: " << path);
+ return false;
+ }
+ for (const StringPiece& resource_name : util::Tokenize(contents, ',')) {
+ options->table_flattener_options.whitelisted_resources.insert(resource_name.to_string());
+ }
+ return true;
+}
+
bool ExtractAppDataFromManifest(OptimizeContext* context, const LoadedApk* apk,
OptimizeOptions* out_options) {
const xml::XmlResource* manifest = apk->GetManifest();
@@ -302,10 +325,12 @@
OptimizeContext context;
OptimizeOptions options;
Maybe<std::string> config_path;
+ Maybe<std::string> whitelist_path;
Maybe<std::string> target_densities;
Maybe<std::string> target_abis;
std::vector<std::string> configs;
std::vector<std::string> split_args;
+ std::unordered_set<std::string> kept_artifacts;
bool verbose = false;
bool print_only = false;
Flags flags =
@@ -320,6 +345,10 @@
"All the resources that would be unused on devices of the given densities will be \n"
"removed from the APK.",
&target_densities)
+ .OptionalFlag("--whitelist-config-path",
+ "Path to the whitelist.cfg file containing whitelisted resources \n"
+ "whose names should not be altered in final resource tables.",
+ &whitelist_path)
.OptionalFlag(
"--target-abis",
"Comma separated list of the CPU ABIs that the APK will be optimized for.\n"
@@ -335,10 +364,17 @@
"Split APK.\nSyntax: path/to/output.apk;<config>[,<config>[...]].\n"
"On Windows, use a semicolon ';' separator instead.",
&split_args)
+ .OptionalFlagList("--keep-artifacts",
+ "Comma separated list of artifacts to keep. If none are specified,\n"
+ "all artifacts will be kept.",
+ &kept_artifacts)
.OptionalSwitch("--enable-sparse-encoding",
"Enables encoding sparse entries using a binary search tree.\n"
"This decreases APK size at the cost of resource retrieval performance.",
&options.table_flattener_options.use_sparse_entries)
+ .OptionalSwitch("--enable-resource-obfuscation",
+ "Enables obfuscation of key string pool to single value",
+ &options.table_flattener_options.collapse_key_stringpool)
.OptionalSwitch("-v", "Enables verbose logging", &verbose);
if (!flags.Parse("aapt2 optimize", args, &std::cerr)) {
@@ -414,6 +450,14 @@
return 0;
}
+ if (!kept_artifacts.empty()) {
+ for (const auto& artifact_str : kept_artifacts) {
+ for (const auto& artifact : util::Tokenize(artifact_str, ',')) {
+ options.kept_artifacts.insert(artifact.to_string());
+ }
+ }
+ }
+
// Since we know that we are going to process the APK (not just print targets), make sure we
// have somewhere to write them to.
if (!options.output_dir) {
@@ -425,6 +469,15 @@
return 1;
}
+ if (options.table_flattener_options.collapse_key_stringpool) {
+ if (whitelist_path) {
+ std::string& path = whitelist_path.value();
+ if (!ExtractWhitelistFromConfig(path, &context, &options)) {
+ return 1;
+ }
+ }
+ }
+
if (!ExtractAppDataFromManifest(&context, apk.get(), &options)) {
return 1;
}
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 2a51df3..a3034df 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -220,12 +220,15 @@
class PackageFlattener {
public:
PackageFlattener(IAaptContext* context, ResourceTablePackage* package,
- const std::map<size_t, std::string>* shared_libs, bool use_sparse_entries)
+ const std::map<size_t, std::string>* shared_libs, bool use_sparse_entries,
+ bool collapse_key_stringpool, const std::set<std::string>& whitelisted_resources)
: context_(context),
diag_(context->GetDiagnostics()),
package_(package),
shared_libs_(shared_libs),
- use_sparse_entries_(use_sparse_entries) {
+ use_sparse_entries_(use_sparse_entries),
+ collapse_key_stringpool_(collapse_key_stringpool),
+ whitelisted_resources_(whitelisted_resources) {
}
bool FlattenPackage(BigBuffer* buffer) {
@@ -494,13 +497,23 @@
// configuration available. Here we reverse this to match the binary
// table.
std::map<ConfigDescription, std::vector<FlatEntry>> config_to_entry_list_map;
- for (ResourceEntry* entry : sorted_entries) {
- const uint32_t key_index = (uint32_t)key_pool_.MakeRef(entry->name).index();
+ // hardcoded string uses characters which make it an invalid resource name
+ const std::string obfuscated_resource_name = "0_resource_name_obfuscated";
+
+ for (ResourceEntry* entry : sorted_entries) {
+ uint32_t local_key_index;
+ if (!collapse_key_stringpool_ ||
+ whitelisted_resources_.find(entry->name) != whitelisted_resources_.end()) {
+ local_key_index = (uint32_t)key_pool_.MakeRef(entry->name).index();
+ } else {
+ // resource isn't whitelisted, add it as obfuscated value
+ local_key_index = (uint32_t)key_pool_.MakeRef(obfuscated_resource_name).index();
+ }
// Group values by configuration.
for (auto& config_value : entry->values) {
config_to_entry_list_map[config_value->config].push_back(
- FlatEntry{entry, config_value->value.get(), key_index});
+ FlatEntry{entry, config_value->value.get(), local_key_index});
}
}
@@ -549,6 +562,8 @@
bool use_sparse_entries_;
StringPool type_pool_;
StringPool key_pool_;
+ bool collapse_key_stringpool_;
+ const std::set<std::string>& whitelisted_resources_;
};
} // namespace
@@ -593,7 +608,8 @@
}
PackageFlattener flattener(context, package.get(), &table->included_packages_,
- options_.use_sparse_entries);
+ options_.use_sparse_entries, options_.collapse_key_stringpool,
+ options_.whitelisted_resources);
if (!flattener.FlattenPackage(&package_buffer)) {
return false;
}
diff --git a/tools/aapt2/format/binary/TableFlattener.h b/tools/aapt2/format/binary/TableFlattener.h
index 88cbddf..c2e1d4b 100644
--- a/tools/aapt2/format/binary/TableFlattener.h
+++ b/tools/aapt2/format/binary/TableFlattener.h
@@ -35,6 +35,14 @@
// This is only available on platforms O+ and will only be respected when
// minSdk is O+.
bool use_sparse_entries = false;
+
+ // When true, the key string pool in the final ResTable
+ // is collapsed to a single entry. All resource entries
+ // have name indices that point to this single value
+ bool collapse_key_stringpool = false;
+
+ // Set of whitelisted resource names to avoid altering in key stringpool
+ std::set<std::string> whitelisted_resources;
};
class TableFlattener : public IResourceTableConsumer {
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index e11890b..f0b80d2 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -127,6 +127,15 @@
<< StringPiece16(actual_name.name, actual_name.nameLen) << "'";
}
+ ResourceName actual_res_name(resName.value());
+
+ if (expected_res_name.entry != actual_res_name.entry ||
+ expected_res_name.package != actual_res_name.package ||
+ expected_res_name.type != actual_res_name.type) {
+ return ::testing::AssertionFailure() << "expected resource '" << expected_res_name.to_string()
+ << "' but got '" << actual_res_name.to_string() << "'";
+ }
+
if (expected_config != config) {
return ::testing::AssertionFailure() << "expected config '" << expected_config
<< "' but got '" << ConfigDescription(config) << "'";
@@ -450,4 +459,113 @@
ASSERT_FALSE(Flatten(context.get(), {}, table.get(), &result));
}
+TEST_F(TableFlattenerTest, ObfuscatingResourceNamesNoWhitelistSucceeds) {
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.test", 0x7f)
+ .AddSimple("com.app.test:id/one", ResourceId(0x7f020000))
+ .AddSimple("com.app.test:id/two", ResourceId(0x7f020001))
+ .AddValue("com.app.test:id/three", ResourceId(0x7f020002),
+ test::BuildReference("com.app.test:id/one", ResourceId(0x7f020000)))
+ .AddValue("com.app.test:integer/one", ResourceId(0x7f030000),
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u))
+ .AddValue("com.app.test:integer/one", test::ParseConfigOrDie("v1"),
+ ResourceId(0x7f030000),
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u))
+ .AddString("com.app.test:string/test", ResourceId(0x7f040000), "foo")
+ .AddString("com.app.test:layout/bar", ResourceId(0x7f050000), "res/layout/bar.xml")
+ .Build();
+
+ TableFlattenerOptions options;
+ options.collapse_key_stringpool = true;
+
+ ResTable res_table;
+
+ ASSERT_TRUE(Flatten(context_.get(), options, table.get(), &res_table));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:id/0_resource_name_obfuscated",
+ ResourceId(0x7f020000), {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:id/0_resource_name_obfuscated",
+ ResourceId(0x7f020001), {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:id/0_resource_name_obfuscated",
+ ResourceId(0x7f020002), {}, Res_value::TYPE_REFERENCE, 0x7f020000u, 0u));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/0_resource_name_obfuscated",
+ ResourceId(0x7f030000), {}, Res_value::TYPE_INT_DEC, 1u,
+ ResTable_config::CONFIG_VERSION));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/0_resource_name_obfuscated",
+ ResourceId(0x7f030000), test::ParseConfigOrDie("v1"), Res_value::TYPE_INT_DEC,
+ 2u, ResTable_config::CONFIG_VERSION));
+
+ std::u16string foo_str = u"foo";
+ ssize_t idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size());
+ ASSERT_GE(idx, 0);
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:string/0_resource_name_obfuscated",
+ ResourceId(0x7f040000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u));
+
+ std::u16string bar_path = u"res/layout/bar.xml";
+ idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size());
+ ASSERT_GE(idx, 0);
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/0_resource_name_obfuscated",
+ ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u));
+}
+
+TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithWhitelistSucceeds) {
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.test", 0x7f)
+ .AddSimple("com.app.test:id/one", ResourceId(0x7f020000))
+ .AddSimple("com.app.test:id/two", ResourceId(0x7f020001))
+ .AddValue("com.app.test:id/three", ResourceId(0x7f020002),
+ test::BuildReference("com.app.test:id/one", ResourceId(0x7f020000)))
+ .AddValue("com.app.test:integer/one", ResourceId(0x7f030000),
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u))
+ .AddValue("com.app.test:integer/one", test::ParseConfigOrDie("v1"),
+ ResourceId(0x7f030000),
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u))
+ .AddString("com.app.test:string/test", ResourceId(0x7f040000), "foo")
+ .AddString("com.app.test:layout/bar", ResourceId(0x7f050000), "res/layout/bar.xml")
+ .Build();
+
+ TableFlattenerOptions options;
+ options.collapse_key_stringpool = true;
+ options.whitelisted_resources.insert("test");
+ options.whitelisted_resources.insert("three");
+ ResTable res_table;
+
+ ASSERT_TRUE(Flatten(context_.get(), options, table.get(), &res_table));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:id/0_resource_name_obfuscated",
+ ResourceId(0x7f020000), {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:id/0_resource_name_obfuscated",
+ ResourceId(0x7f020001), {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:id/three", ResourceId(0x7f020002), {},
+ Res_value::TYPE_REFERENCE, 0x7f020000u, 0u));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/0_resource_name_obfuscated",
+ ResourceId(0x7f030000), {}, Res_value::TYPE_INT_DEC, 1u,
+ ResTable_config::CONFIG_VERSION));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/0_resource_name_obfuscated",
+ ResourceId(0x7f030000), test::ParseConfigOrDie("v1"), Res_value::TYPE_INT_DEC,
+ 2u, ResTable_config::CONFIG_VERSION));
+
+ std::u16string foo_str = u"foo";
+ ssize_t idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size());
+ ASSERT_GE(idx, 0);
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:string/test", ResourceId(0x7f040000), {},
+ Res_value::TYPE_STRING, (uint32_t)idx, 0u));
+
+ std::u16string bar_path = u"res/layout/bar.xml";
+ idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size());
+ ASSERT_GE(idx, 0);
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/0_resource_name_obfuscated",
+ ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/integration-tests/StaticLibTest/App/AndroidManifest.xml b/tools/aapt2/integration-tests/StaticLibTest/App/AndroidManifest.xml
index a5f202d..c8f4bda 100644
--- a/tools/aapt2/integration-tests/StaticLibTest/App/AndroidManifest.xml
+++ b/tools/aapt2/integration-tests/StaticLibTest/App/AndroidManifest.xml
@@ -21,7 +21,7 @@
<uses-permission-sdk-23 android:name="android.permission.TEST" android:maxSdkVersion="22" />
<application>
- <activity android:name=".MyActivity">
+ <activity android:name=".MyActivity" android:id="@+id/sample_generated_id">
<layout android:defaultHeight="500dp"
android:defaultWidth="600dp" />
</activity>
diff --git a/tools/aapt2/integration-tests/StaticLibTest/App/res/layout/main.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/layout/main.xml
index aaa884b..5a73429 100644
--- a/tools/aapt2/integration-tests/StaticLibTest/App/res/layout/main.xml
+++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/layout/main.xml
@@ -19,7 +19,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
- <fragment class="android.test.sample.App$Inner" />
+ <fragment class="android.test.sample.App$Inner" android:id="@id/sample_generated_id"/>
<variable name="user" type="com.android.User" />
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index de4fb73..a68df1d 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -346,30 +346,15 @@
return true;
}
-class FullyQualifiedClassNameVisitor : public xml::Visitor {
- public:
- using xml::Visitor::Visit;
-
- explicit FullyQualifiedClassNameVisitor(const StringPiece& package) : package_(package) {}
-
- void Visit(xml::Element* el) override {
- for (xml::Attribute& attr : el->attributes) {
- if (attr.namespace_uri == xml::kSchemaAndroid &&
- class_attributes_.find(attr.name) != class_attributes_.end()) {
- if (Maybe<std::string> new_value = util::GetFullyQualifiedClassName(package_, attr.value)) {
- attr.value = std::move(new_value.value());
- }
- }
+static void FullyQualifyClassName(const StringPiece& package, const StringPiece& attr_ns,
+ const StringPiece& attr_name, xml::Element* el) {
+ xml::Attribute* attr = el->FindAttribute(attr_ns, attr_name);
+ if (attr != nullptr) {
+ if (Maybe<std::string> new_value = util::GetFullyQualifiedClassName(package, attr->value)) {
+ attr->value = std::move(new_value.value());
}
-
- // Super implementation to iterate over the children.
- xml::Visitor::Visit(el);
}
-
- private:
- StringPiece package_;
- std::unordered_set<StringPiece> class_attributes_ = {"name"};
-};
+}
static bool RenameManifestPackage(const StringPiece& package_override, xml::Element* manifest_el) {
xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
@@ -381,8 +366,25 @@
std::string original_package = std::move(attr->value);
attr->value = package_override.to_string();
- FullyQualifiedClassNameVisitor visitor(original_package);
- manifest_el->Accept(&visitor);
+ xml::Element* application_el = manifest_el->FindChild({}, "application");
+ if (application_el != nullptr) {
+ FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", application_el);
+ FullyQualifyClassName(original_package, xml::kSchemaAndroid, "backupAgent", application_el);
+
+ for (xml::Element* child_el : application_el->GetChildElements()) {
+ if (child_el->namespace_uri.empty()) {
+ if (child_el->name == "activity" || child_el->name == "activity-alias" ||
+ child_el->name == "provider" || child_el->name == "receiver" ||
+ child_el->name == "service") {
+ FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", child_el);
+ }
+
+ if (child_el->name == "activity-alias") {
+ FullyQualifyClassName(original_package, xml::kSchemaAndroid, "targetActivity", child_el);
+ }
+ }
+ }
+ }
return true;
}
@@ -404,6 +406,25 @@
root->InsertChild(0, std::move(uses_sdk));
}
+ if (options_.compile_sdk_version) {
+ xml::Attribute* attr = root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersion");
+
+ // Make sure we un-compile the value if it was set to something else.
+ attr->compiled_value = {};
+
+ attr->value = options_.compile_sdk_version.value();
+ }
+
+ if (options_.compile_sdk_version_codename) {
+ xml::Attribute* attr =
+ root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename");
+
+ // Make sure we un-compile the value if it was set to something else.
+ attr->compiled_value = {};
+
+ attr->value = options_.compile_sdk_version_codename.value();
+ }
+
xml::XmlActionExecutor executor;
if (!BuildRules(&executor, context->GetDiagnostics())) {
return false;
diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h
index 470f65e..f5715f6 100644
--- a/tools/aapt2/link/ManifestFixer.h
+++ b/tools/aapt2/link/ManifestFixer.h
@@ -29,22 +29,42 @@
namespace aapt {
struct ManifestFixerOptions {
+ // The minimum SDK version to set if no 'android:minSdkVersion' is defined in a <uses-sdk> tag.
Maybe<std::string> min_sdk_version_default;
+
+ // The target SDK version to set if no 'android:targetSdkVersion' is defined in a <uses-sdk> tag.
Maybe<std::string> target_sdk_version_default;
+
+ // The Android package to use instead of the one defined in 'package' in <manifest>.
+ // This also renames all relative package/class names in the manifest to fully qualified
+ // Java names.
Maybe<std::string> rename_manifest_package;
+
+ // The Android package to use instead of the one defined in 'android:targetPackage' in
+ // <instrumentation>.
Maybe<std::string> rename_instrumentation_target_package;
+
+ // The version name to set if 'android:versionName' is not defined in <manifest>.
Maybe<std::string> version_name_default;
+
+ // The version code to set if 'android:versionCode' is not defined in <manifest>.
Maybe<std::string> version_code_default;
+
+ // The version of the framework being compiled against to set for 'android:compileSdkVersion' in
+ // the <manifest> tag.
+ Maybe<std::string> compile_sdk_version;
+
+ // The version codename of the framework being compiled against to set for
+ // 'android:compileSdkVersionCodename' in the <manifest> tag.
+ Maybe<std::string> compile_sdk_version_codename;
};
-/**
- * Verifies that the manifest is correctly formed and inserts defaults
- * where specified with ManifestFixerOptions.
- */
+// Verifies that the manifest is correctly formed and inserts defaults where specified with
+// ManifestFixerOptions.
class ManifestFixer : public IXmlResourceConsumer {
public:
- explicit ManifestFixer(const ManifestFixerOptions& options)
- : options_(options) {}
+ explicit ManifestFixer(const ManifestFixerOptions& options) : options_(options) {
+ }
bool Consume(IAaptContext* context, xml::XmlResource* doc) override;
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index da7f410..1320dcd 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -19,7 +19,12 @@
#include "test/Test.h"
using ::android::StringPiece;
+using ::testing::Eq;
+using ::testing::Gt;
+using ::testing::IsNull;
+using ::testing::Ne;
using ::testing::NotNull;
+using ::testing::StrEq;
namespace aapt {
@@ -72,22 +77,20 @@
};
TEST_F(ManifestFixerTest, EnsureManifestIsRootTag) {
- EXPECT_EQ(nullptr, Verify("<other-tag />"));
- EXPECT_EQ(nullptr, Verify("<ns:manifest xmlns:ns=\"com\" />"));
- EXPECT_NE(nullptr, Verify("<manifest package=\"android\"></manifest>"));
+ EXPECT_THAT(Verify("<other-tag />"), IsNull());
+ EXPECT_THAT(Verify("<ns:manifest xmlns:ns=\"com\" />"), IsNull());
+ EXPECT_THAT(Verify("<manifest package=\"android\"></manifest>"), NotNull());
}
TEST_F(ManifestFixerTest, EnsureManifestHasPackage) {
- EXPECT_NE(nullptr, Verify("<manifest package=\"android\" />"));
- EXPECT_NE(nullptr, Verify("<manifest package=\"com.android\" />"));
- EXPECT_NE(nullptr, Verify("<manifest package=\"com.android.google\" />"));
- EXPECT_EQ(nullptr,
- Verify("<manifest package=\"com.android.google.Class$1\" />"));
- EXPECT_EQ(nullptr, Verify("<manifest "
- "xmlns:android=\"http://schemas.android.com/apk/"
- "res/android\" "
- "android:package=\"com.android\" />"));
- EXPECT_EQ(nullptr, Verify("<manifest package=\"@string/str\" />"));
+ EXPECT_THAT(Verify("<manifest package=\"android\" />"), NotNull());
+ EXPECT_THAT(Verify("<manifest package=\"com.android\" />"), NotNull());
+ EXPECT_THAT(Verify("<manifest package=\"com.android.google\" />"), NotNull());
+ EXPECT_THAT(Verify("<manifest package=\"com.android.google.Class$1\" />"), IsNull());
+ EXPECT_THAT(Verify("<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" "
+ "android:package=\"com.android\" />"),
+ IsNull());
+ EXPECT_THAT(Verify("<manifest package=\"@string/str\" />"), IsNull());
}
TEST_F(ManifestFixerTest, AllowMetaData) {
@@ -105,7 +108,7 @@
</application>
<instrumentation android:name=".Go"><meta-data /></instrumentation>
</manifest>)EOF");
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
}
TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) {
@@ -117,21 +120,21 @@
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="21" />
</manifest>)EOF",
options);
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
xml::Element* el;
xml::Attribute* attr;
el = doc->root.get();
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
el = el->FindChild({}, "uses-sdk");
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ("7", attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("7"));
attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ("21", attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("21"));
doc = VerifyWithOptions(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -139,18 +142,18 @@
<uses-sdk android:targetSdkVersion="21" />
</manifest>)EOF",
options);
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
el = doc->root.get();
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
el = el->FindChild({}, "uses-sdk");
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ("8", attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("8"));
attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ("21", attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("21"));
doc = VerifyWithOptions(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -158,35 +161,35 @@
<uses-sdk />
</manifest>)EOF",
options);
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
el = doc->root.get();
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
el = el->FindChild({}, "uses-sdk");
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ("8", attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("8"));
attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ("22", attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("22"));
doc = VerifyWithOptions(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android" />)EOF",
options);
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
el = doc->root.get();
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
el = el->FindChild({}, "uses-sdk");
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ("8", attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("8"));
attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ("22", attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("22"));
}
TEST_F(ManifestFixerTest, UsesSdkMustComeBeforeApplication) {
@@ -197,17 +200,17 @@
<application android:name=".MainApplication" />
</manifest>)EOF",
options);
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
xml::Element* manifest_el = doc->root.get();
- ASSERT_NE(nullptr, manifest_el);
+ ASSERT_THAT(manifest_el, NotNull());
ASSERT_EQ("manifest", manifest_el->name);
xml::Element* application_el = manifest_el->FindChild("", "application");
- ASSERT_NE(nullptr, application_el);
+ ASSERT_THAT(application_el, NotNull());
xml::Element* uses_sdk_el = manifest_el->FindChild("", "uses-sdk");
- ASSERT_NE(nullptr, uses_sdk_el);
+ ASSERT_THAT(uses_sdk_el, NotNull());
// Check that the uses_sdk_el comes before application_el in the children
// vector.
@@ -225,12 +228,12 @@
return child.get() == application_el;
});
- ASSERT_NE(manifest_el->children.end(), uses_sdk_iter);
- ASSERT_NE(manifest_el->children.end(), application_iter);
+ ASSERT_THAT(uses_sdk_iter, Ne(manifest_el->children.end()));
+ ASSERT_THAT(application_iter, Ne(manifest_el->children.end()));
// The distance should be positive, meaning uses_sdk_iter comes before
// application_iter.
- EXPECT_GT(std::distance(uses_sdk_iter, application_iter), 0);
+ EXPECT_THAT(std::distance(uses_sdk_iter, application_iter), Gt(0));
}
TEST_F(ManifestFixerTest, RenameManifestPackageAndFullyQualifyClasses) {
@@ -240,48 +243,56 @@
std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android">
+ <uses-split android:name="feature_a" />
<application android:name=".MainApplication" text="hello">
<activity android:name=".activity.Start" />
<receiver android:name="com.google.android.Receiver" />
</application>
</manifest>)EOF",
options);
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
- xml::Element* manifestEl = doc->root.get();
- ASSERT_NE(nullptr, manifestEl);
+ xml::Element* manifest_el = doc->root.get();
+ ASSERT_THAT(manifest_el, NotNull());
xml::Attribute* attr = nullptr;
- attr = manifestEl->FindAttribute({}, "package");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::string("com.android"), attr->value);
+ attr = manifest_el->FindAttribute({}, "package");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("com.android"));
- xml::Element* applicationEl = manifestEl->FindChild({}, "application");
- ASSERT_NE(nullptr, applicationEl);
+ xml::Element* uses_split_el = manifest_el->FindChild({}, "uses-split");
+ ASSERT_THAT(uses_split_el, NotNull());
+ attr = uses_split_el->FindAttribute(xml::kSchemaAndroid, "name");
+ ASSERT_THAT(attr, NotNull());
+ // This should NOT have been affected.
+ EXPECT_THAT(attr->value, StrEq("feature_a"));
- attr = applicationEl->FindAttribute(xml::kSchemaAndroid, "name");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::string("android.MainApplication"), attr->value);
+ xml::Element* application_el = manifest_el->FindChild({}, "application");
+ ASSERT_THAT(application_el, NotNull());
- attr = applicationEl->FindAttribute({}, "text");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::string("hello"), attr->value);
+ attr = application_el->FindAttribute(xml::kSchemaAndroid, "name");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("android.MainApplication"));
+
+ attr = application_el->FindAttribute({}, "text");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("hello"));
xml::Element* el;
- el = applicationEl->FindChild({}, "activity");
- ASSERT_NE(nullptr, el);
+ el = application_el->FindChild({}, "activity");
+ ASSERT_THAT(el, NotNull());
attr = el->FindAttribute(xml::kSchemaAndroid, "name");
- ASSERT_NE(nullptr, el);
- EXPECT_EQ(std::string("android.activity.Start"), attr->value);
+ ASSERT_THAT(el, NotNull());
+ EXPECT_THAT(attr->value, StrEq("android.activity.Start"));
- el = applicationEl->FindChild({}, "receiver");
- ASSERT_NE(nullptr, el);
+ el = application_el->FindChild({}, "receiver");
+ ASSERT_THAT(el, NotNull());
attr = el->FindAttribute(xml::kSchemaAndroid, "name");
- ASSERT_NE(nullptr, el);
- EXPECT_EQ(std::string("com.google.android.Receiver"), attr->value);
+ ASSERT_THAT(el, NotNull());
+ EXPECT_THAT(attr->value, StrEq("com.google.android.Receiver"));
}
TEST_F(ManifestFixerTest,
@@ -295,19 +306,19 @@
<instrumentation android:name=".TestRunner" android:targetPackage="android" />
</manifest>)EOF",
options);
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
xml::Element* manifest_el = doc->root.get();
- ASSERT_NE(nullptr, manifest_el);
+ ASSERT_THAT(manifest_el, NotNull());
xml::Element* instrumentation_el =
manifest_el->FindChild({}, "instrumentation");
- ASSERT_NE(nullptr, instrumentation_el);
+ ASSERT_THAT(instrumentation_el, NotNull());
xml::Attribute* attr =
instrumentation_el->FindAttribute(xml::kSchemaAndroid, "targetPackage");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::string("com.android"), attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("com.android"));
}
TEST_F(ManifestFixerTest, UseDefaultVersionNameAndCode) {
@@ -319,41 +330,39 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android" />)EOF",
options);
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
xml::Element* manifest_el = doc->root.get();
- ASSERT_NE(nullptr, manifest_el);
+ ASSERT_THAT(manifest_el, NotNull());
xml::Attribute* attr =
manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::string("Beta"), attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("Beta"));
attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::string("0x10000000"), attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("0x10000000"));
}
TEST_F(ManifestFixerTest, EnsureManifestAttributesAreTyped) {
- EXPECT_EQ(nullptr,
- Verify("<manifest package=\"android\" coreApp=\"hello\" />"));
- EXPECT_EQ(nullptr,
- Verify("<manifest package=\"android\" coreApp=\"1dp\" />"));
+ EXPECT_THAT(Verify("<manifest package=\"android\" coreApp=\"hello\" />"), IsNull());
+ EXPECT_THAT(Verify("<manifest package=\"android\" coreApp=\"1dp\" />"), IsNull());
std::unique_ptr<xml::XmlResource> doc =
Verify("<manifest package=\"android\" coreApp=\"true\" />");
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
xml::Element* el = doc->root.get();
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
- EXPECT_EQ("manifest", el->name);
+ EXPECT_THAT(el->name, StrEq("manifest"));
xml::Attribute* attr = el->FindAttribute("", "coreApp");
- ASSERT_NE(nullptr, attr);
+ ASSERT_THAT(attr, NotNull());
- EXPECT_NE(nullptr, attr->compiled_value);
- EXPECT_NE(nullptr, ValueCast<BinaryPrimitive>(attr->compiled_value.get()));
+ EXPECT_THAT(attr->compiled_value, NotNull());
+ EXPECT_THAT(ValueCast<BinaryPrimitive>(attr->compiled_value.get()), NotNull());
}
TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) {
@@ -368,21 +377,21 @@
<uses-feature android:glEsVersion="2" />
</feature-group>
</manifest>)EOF";
- EXPECT_NE(nullptr, Verify(input));
+ EXPECT_THAT(Verify(input), NotNull());
input = R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android">
<uses-feature android:name="feature" android:glEsVersion="1" />
</manifest>)EOF";
- EXPECT_EQ(nullptr, Verify(input));
+ EXPECT_THAT(Verify(input), IsNull());
input = R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android">
<uses-feature />
</manifest>)EOF";
- EXPECT_EQ(nullptr, Verify(input));
+ EXPECT_THAT(Verify(input), IsNull());
input = R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -391,7 +400,7 @@
<uses-feature android:name="feature" android:glEsVersion="1" />
</feature-group>
</manifest>)EOF";
- EXPECT_EQ(nullptr, Verify(input));
+ EXPECT_THAT(Verify(input), IsNull());
input = R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -400,7 +409,7 @@
<uses-feature />
</feature-group>
</manifest>)EOF";
- EXPECT_EQ(nullptr, Verify(input));
+ EXPECT_THAT(Verify(input), IsNull());
}
TEST_F(ManifestFixerTest, IgnoreNamespacedElements) {
@@ -409,7 +418,7 @@
package="android">
<special:tag whoo="true" xmlns:special="http://google.com" />
</manifest>)EOF";
- EXPECT_NE(nullptr, Verify(input));
+ EXPECT_THAT(Verify(input), NotNull());
}
TEST_F(ManifestFixerTest, DoNotIgnoreNonNamespacedElements) {
@@ -418,7 +427,7 @@
package="android">
<tag whoo="true" />
</manifest>)EOF";
- EXPECT_EQ(nullptr, Verify(input));
+ EXPECT_THAT(Verify(input), IsNull());
}
TEST_F(ManifestFixerTest, SupportKeySets) {
@@ -439,4 +448,23 @@
EXPECT_THAT(Verify(input), NotNull());
}
+TEST_F(ManifestFixerTest, InsertCompileSdkVersions) {
+ std::string input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android" />)";
+ ManifestFixerOptions options;
+ options.compile_sdk_version = {"28"};
+ options.compile_sdk_version_codename = {"P"};
+
+ std::unique_ptr<xml::XmlResource> manifest = VerifyWithOptions(input, options);
+ ASSERT_THAT(manifest, NotNull());
+
+ xml::Attribute* attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersion");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("28"));
+
+ attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("P"));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/link/ProductFilter_test.cpp b/tools/aapt2/link/ProductFilter_test.cpp
index 379ad26..86dd56a 100644
--- a/tools/aapt2/link/ProductFilter_test.cpp
+++ b/tools/aapt2/link/ProductFilter_test.cpp
@@ -73,7 +73,7 @@
test::ValueBuilder<Id>().SetSource(Source("tablet.xml")).Build(),
context->GetDiagnostics()));
- ProductFilter filter({});
+ ProductFilter filter(std::unordered_set<std::string>{});
ASSERT_TRUE(filter.Consume(context.get(), &table));
EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<Id>(
@@ -123,7 +123,7 @@
test::ValueBuilder<Id>().SetSource(Source("default.xml")).Build(),
context->GetDiagnostics()));
- ProductFilter filter({});
+ ProductFilter filter(std::unordered_set<std::string>{});
ASSERT_FALSE(filter.Consume(context.get(), &table));
}
diff --git a/tools/aapt2/optimize/MultiApkGenerator.cpp b/tools/aapt2/optimize/MultiApkGenerator.cpp
index 473693c..da3b879 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator.cpp
@@ -84,6 +84,9 @@
}
IDiagnostics* GetDiagnostics() override {
+ if (source_diag_) {
+ return source_diag_.get();
+ }
return context_->GetDiagnostics();
}
@@ -111,8 +114,13 @@
min_sdk_ = min_sdk;
}
+ void SetSource(const Source& source) {
+ source_diag_ = util::make_unique<SourcePathDiagnostics>(source, context_->GetDiagnostics());
+ }
+
private:
IAaptContext* context_;
+ std::unique_ptr<SourcePathDiagnostics> source_diag_;
int min_sdk_ = -1;
};
@@ -123,78 +131,124 @@
bool MultiApkGenerator::FromBaseApk(const MultiApkGeneratorOptions& options) {
// TODO(safarmer): Handle APK version codes for the generated APKs.
- IDiagnostics* diag = context_->GetDiagnostics();
const PostProcessingConfiguration& config = options.config;
const std::string& apk_name = file::GetFilename(apk_->GetSource().path).to_string();
const StringPiece ext = file::GetExtension(apk_name);
const std::string base_name = apk_name.substr(0, apk_name.rfind(ext.to_string()));
+ std::unordered_set<std::string> artifacts_to_keep = options.kept_artifacts;
+ std::unordered_set<std::string> filtered_artifacts;
+ std::unordered_set<std::string> kept_artifacts;
+
// For now, just write out the stripped APK since ABI splitting doesn't modify anything else.
for (const Artifact& artifact : config.artifacts) {
+ SourcePathDiagnostics diag{{apk_name}, context_->GetDiagnostics()};
+
FilterChain filters;
if (!artifact.name && !config.artifact_format) {
- diag->Error(
+ diag.Error(
DiagMessage() << "Artifact does not have a name and no global name template defined");
return false;
}
- Maybe<std::string> artifact_name =
- (artifact.name) ? artifact.Name(apk_name, diag)
- : artifact.ToArtifactName(config.artifact_format.value(), apk_name, diag);
+ Maybe<std::string> maybe_artifact_name =
+ (artifact.name) ? artifact.Name(apk_name, &diag)
+ : artifact.ToArtifactName(config.artifact_format.value(), apk_name, &diag);
- if (!artifact_name) {
- diag->Error(DiagMessage() << "Could not determine split APK artifact name");
+ if (!maybe_artifact_name) {
+ diag.Error(DiagMessage() << "Could not determine split APK artifact name");
return false;
}
+ const std::string& artifact_name = maybe_artifact_name.value();
+
+ ContextWrapper wrapped_context{context_};
+ wrapped_context.SetSource({artifact_name});
+
+ if (!options.kept_artifacts.empty()) {
+ const auto& it = artifacts_to_keep.find(artifact_name);
+ if (it == artifacts_to_keep.end()) {
+ filtered_artifacts.insert(artifact_name);
+ if (context_->IsVerbose()) {
+ context_->GetDiagnostics()->Note(DiagMessage(artifact_name) << "skipping artifact");
+ }
+ continue;
+ } else {
+ artifacts_to_keep.erase(it);
+ kept_artifacts.insert(artifact_name);
+ }
+ }
+
std::unique_ptr<ResourceTable> table =
- FilterTable(artifact, config, *apk_->GetResourceTable(), &filters);
+ FilterTable(artifact, config, *apk_->GetResourceTable(), &wrapped_context, &filters);
if (!table) {
return false;
}
std::unique_ptr<XmlResource> manifest;
- if (!UpdateManifest(artifact, config, &manifest, diag)) {
- diag->Error(DiagMessage() << "could not update AndroidManifest.xml for "
- << artifact_name.value());
+ if (!UpdateManifest(artifact, config, &manifest, &diag)) {
+ diag.Error(DiagMessage() << "could not update AndroidManifest.xml for output artifact");
return false;
}
std::string out = options.out_dir;
if (!file::mkdirs(out)) {
- context_->GetDiagnostics()->Warn(DiagMessage() << "could not create out dir: " << out);
+ diag.Warn(DiagMessage() << "could not create out dir: " << out);
}
- file::AppendPath(&out, artifact_name.value());
+ file::AppendPath(&out, artifact_name);
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage() << "Generating split: " << out);
+ diag.Note(DiagMessage() << "Generating split: " << out);
}
- std::unique_ptr<IArchiveWriter> writer =
- CreateZipFileArchiveWriter(context_->GetDiagnostics(), out);
+ std::unique_ptr<IArchiveWriter> writer = CreateZipFileArchiveWriter(&diag, out);
if (context_->IsVerbose()) {
- diag->Note(DiagMessage() << "Writing output: " << out);
+ diag.Note(DiagMessage() << "Writing output: " << out);
}
- if (!apk_->WriteToArchive(context_, table.get(), options.table_flattener_options, &filters,
- writer.get(), manifest.get())) {
+ if (!apk_->WriteToArchive(&wrapped_context, table.get(), options.table_flattener_options,
+ &filters, writer.get(), manifest.get())) {
return false;
}
}
+ // Make sure all of the requested artifacts were valid. If there are any kept artifacts left,
+ // either the config or the command line was wrong.
+ if (!artifacts_to_keep.empty()) {
+ context_->GetDiagnostics()->Error(
+ DiagMessage() << "The configuration and command line to filter artifacts do not match");
+
+ context_->GetDiagnostics()->Error(DiagMessage() << kept_artifacts.size() << " kept:");
+ for (const auto& artifact : kept_artifacts) {
+ context_->GetDiagnostics()->Error(DiagMessage() << " " << artifact);
+ }
+
+ context_->GetDiagnostics()->Error(DiagMessage() << filtered_artifacts.size() << " filtered:");
+ for (const auto& artifact : filtered_artifacts) {
+ context_->GetDiagnostics()->Error(DiagMessage() << " " << artifact);
+ }
+
+ context_->GetDiagnostics()->Error(DiagMessage() << artifacts_to_keep.size() << " missing:");
+ for (const auto& artifact : artifacts_to_keep) {
+ context_->GetDiagnostics()->Error(DiagMessage() << " " << artifact);
+ }
+
+ return false;
+ }
+
return true;
}
std::unique_ptr<ResourceTable> MultiApkGenerator::FilterTable(
const configuration::Artifact& artifact,
const configuration::PostProcessingConfiguration& config, const ResourceTable& old_table,
- FilterChain* filters) {
+ IAaptContext* context, FilterChain* filters) {
TableSplitterOptions splits;
AxisConfigFilter axis_filter;
- ContextWrapper wrappedContext{context_};
+ ContextWrapper wrapped_context{context};
if (artifact.abi_group) {
const std::string& group_name = artifact.abi_group.value();
@@ -202,8 +256,8 @@
auto group = config.abi_groups.find(group_name);
// TODO: Remove validation when configuration parser ensures referential integrity.
if (group == config.abi_groups.end()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "could not find referenced ABI group '"
- << group_name << "'");
+ context->GetDiagnostics()->Error(DiagMessage() << "could not find referenced ABI group '"
+ << group_name << "'");
return {};
}
filters->AddFilter(AbiFilter::FromAbiList(group->second));
@@ -215,13 +269,13 @@
auto group = config.screen_density_groups.find(group_name);
// TODO: Remove validation when configuration parser ensures referential integrity.
if (group == config.screen_density_groups.end()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "could not find referenced group '"
- << group_name << "'");
+ context->GetDiagnostics()->Error(DiagMessage()
+ << "could not find referenced group '" << group_name << "'");
return {};
}
const std::vector<ConfigDescription>& densities = group->second;
- for(const auto& density_config : densities) {
+ for (const auto& density_config : densities) {
splits.preferred_densities.push_back(density_config.density);
}
}
@@ -231,8 +285,8 @@
auto group = config.locale_groups.find(group_name);
// TODO: Remove validation when configuration parser ensures referential integrity.
if (group == config.locale_groups.end()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "could not find referenced group '"
- << group_name << "'");
+ context->GetDiagnostics()->Error(DiagMessage()
+ << "could not find referenced group '" << group_name << "'");
return {};
}
@@ -243,16 +297,16 @@
splits.config_filter = &axis_filter;
}
- Maybe<AndroidSdk> sdk = GetAndroidSdk(artifact, config, context_->GetDiagnostics());
+ Maybe<AndroidSdk> sdk = GetAndroidSdk(artifact, config, context->GetDiagnostics());
if (sdk && sdk.value().min_sdk_version) {
- wrappedContext.SetMinSdkVersion(sdk.value().min_sdk_version.value());
+ wrapped_context.SetMinSdkVersion(sdk.value().min_sdk_version.value());
}
std::unique_ptr<ResourceTable> table = old_table.Clone();
VersionCollapser collapser;
- if (!collapser.Consume(&wrappedContext, table.get())) {
- context_->GetDiagnostics()->Error(DiagMessage() << "Failed to strip versioned resources");
+ if (!collapser.Consume(&wrapped_context, table.get())) {
+ context->GetDiagnostics()->Error(DiagMessage() << "Failed to strip versioned resources");
return {};
}
diff --git a/tools/aapt2/optimize/MultiApkGenerator.h b/tools/aapt2/optimize/MultiApkGenerator.h
index e6546ee..dedb610 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.h
+++ b/tools/aapt2/optimize/MultiApkGenerator.h
@@ -17,6 +17,10 @@
#ifndef AAPT2_APKSPLITTER_H
#define AAPT2_APKSPLITTER_H
+#include <memory>
+#include <string>
+#include <unordered_set>
+
#include "Diagnostics.h"
#include "LoadedApk.h"
#include "configuration/ConfigurationParser.h"
@@ -27,6 +31,7 @@
std::string out_dir;
configuration::PostProcessingConfiguration config;
TableFlattenerOptions table_flattener_options;
+ std::unordered_set<std::string> kept_artifacts;
};
/**
@@ -47,7 +52,7 @@
virtual std::unique_ptr<ResourceTable> FilterTable(
const configuration::Artifact& artifact,
const configuration::PostProcessingConfiguration& config, const ResourceTable& old_table,
- FilterChain* chain);
+ IAaptContext* context, FilterChain* chain);
private:
IDiagnostics* GetDiagnostics() {
diff --git a/tools/aapt2/optimize/MultiApkGenerator_test.cpp b/tools/aapt2/optimize/MultiApkGenerator_test.cpp
index 30c9146..2d303e2 100644
--- a/tools/aapt2/optimize/MultiApkGenerator_test.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator_test.cpp
@@ -63,8 +63,8 @@
std::unique_ptr<ResourceTable> FilterTable(
const configuration::Artifact& artifact,
const configuration::PostProcessingConfiguration& config, const ResourceTable& old_table,
- FilterChain* pChain) override {
- return MultiApkGenerator::FilterTable(artifact, config, old_table, pChain);
+ IAaptContext* context, FilterChain* filter_chain) override {
+ return MultiApkGenerator::FilterTable(artifact, config, old_table, context, filter_chain);
}
};
@@ -128,7 +128,7 @@
MultiApkGeneratorWrapper generator{&apk, ctx.get()};
std::unique_ptr<ResourceTable> split =
- generator.FilterTable(x64, config, *apk.GetResourceTable(), &chain);
+ generator.FilterTable(x64, config, *apk.GetResourceTable(), ctx.get(), &chain);
ResourceTable* new_table = split.get();
EXPECT_THAT(ValueForConfig(new_table, mdpi_), IsNull());
@@ -169,7 +169,7 @@
MultiApkGeneratorWrapper generator{&apk, ctx.get()};;
std::unique_ptr<ResourceTable> split =
- generator.FilterTable(x64, config, *apk.GetResourceTable(), &chain);
+ generator.FilterTable(x64, config, *apk.GetResourceTable(), ctx.get(), &chain);
ResourceTable* new_table = split.get();
EXPECT_THAT(ValueForConfig(new_table, mdpi_), IsNull());
@@ -204,7 +204,7 @@
MultiApkGeneratorWrapper generator{&apk, ctx.get()};
std::unique_ptr<ResourceTable> split =
- generator.FilterTable(x64, config, *apk.GetResourceTable(), &chain);
+ generator.FilterTable(x64, config, *apk.GetResourceTable(), ctx.get(), &chain);
ResourceTable* new_table = split.get();
EXPECT_THAT(ValueForConfig(new_table, mdpi_), IsNull());
diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h
index 4a2181e..b676efb 100644
--- a/tools/aapt2/process/SymbolTable.h
+++ b/tools/aapt2/process/SymbolTable.h
@@ -199,6 +199,10 @@
std::unique_ptr<SymbolTable::Symbol> FindByReference(
const Reference& ref) override;
+ android::AssetManager* GetAssetManager() {
+ return &assets_;
+ }
+
private:
android::AssetManager assets_;
diff --git a/tools/aapt2/text/Unicode_test.cpp b/tools/aapt2/text/Unicode_test.cpp
index a8e797c..16bc2e8 100644
--- a/tools/aapt2/text/Unicode_test.cpp
+++ b/tools/aapt2/text/Unicode_test.cpp
@@ -63,6 +63,7 @@
EXPECT_FALSE(IsValidResourceEntryName("Føø/Bar"));
EXPECT_FALSE(IsValidResourceEntryName("Føø:Bar"));
EXPECT_FALSE(IsValidResourceEntryName("Føø;Bar"));
+ EXPECT_FALSE(IsValidResourceEntryName("0_resource_name_obfuscated"));
}
} // namespace text
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index b0cf44a..fddb6b8 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -418,6 +418,15 @@
return nullptr;
}
+Attribute* Element::FindOrCreateAttribute(const StringPiece& ns, const StringPiece& name) {
+ Attribute* attr = FindAttribute(ns, name);
+ if (attr == nullptr) {
+ attributes.push_back(Attribute{ns.to_string(), name.to_string()});
+ attr = &attributes.back();
+ }
+ return attr;
+}
+
Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
return FindChildWithAttribute(ns, name, {}, {}, {});
}
diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h
index cf06ba5..8f382961 100644
--- a/tools/aapt2/xml/XmlDom.h
+++ b/tools/aapt2/xml/XmlDom.h
@@ -100,6 +100,8 @@
Attribute* FindAttribute(const android::StringPiece& ns, const android::StringPiece& name);
const Attribute* FindAttribute(const android::StringPiece& ns,
const android::StringPiece& name) const;
+ Attribute* FindOrCreateAttribute(const android::StringPiece& ns,
+ const android::StringPiece& name);
Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name);
const Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name) const;
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index fd42033..421e545 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -940,11 +940,14 @@
for f in found.values():
takes_handler = False
+ takes_exec = False
for m in by_name[f.name]:
if "android.os.Handler" in m.args:
takes_handler = True
- if not takes_handler:
- warn(clazz, f, "L1", "Registration methods should have overload that accepts delivery Handler")
+ if "java.util.concurrent.Executor" in m.args:
+ takes_exec = True
+ if not takes_exec:
+ warn(clazz, f, "L1", "Registration methods should have overload that accepts delivery Executor")
def verify_context_first(clazz):
@@ -968,7 +971,7 @@
for a in m.args:
if a.endswith("Callback") or a.endswith("Callbacks") or a.endswith("Listener"):
found = True
- elif found and a != "android.os.Handler":
+ elif found and a != "android.os.Handler" and a != "java.util.concurrent.Executor":
warn(clazz, m, "M3", "Listeners should always be at end of argument list")
@@ -1218,6 +1221,18 @@
unique_binary_op(m, m.name[:-6]) # Remove 'Assign' suffix
+def verify_collections_over_arrays(clazz):
+ """Warn that [] should be Collections."""
+
+ safe = ["java.lang.String[]","byte[]","short[]","int[]","long[]","float[]","double[]","boolean[]","char[]"]
+ for m in clazz.methods:
+ if m.typ.endswith("[]") and m.typ not in safe:
+ warn(clazz, m, None, "Method should return Collection<> (or subclass) instead of raw array")
+ for arg in m.args:
+ if arg.endswith("[]") and arg not in safe:
+ warn(clazz, m, None, "Method argument should be Collection<> (or subclass) instead of raw array")
+
+
def examine_clazz(clazz):
"""Find all style issues in the given class."""
@@ -1260,7 +1275,7 @@
verify_manager(clazz)
verify_boxed(clazz)
verify_static_utils(clazz)
- verify_overload_args(clazz)
+ # verify_overload_args(clazz)
verify_callback_handlers(clazz)
verify_context_first(clazz)
verify_listener_last(clazz)
@@ -1274,6 +1289,7 @@
verify_closable(clazz)
verify_member_name_not_kotlin_keyword(clazz)
verify_method_name_not_kotlin_operator(clazz)
+ verify_collections_over_arrays(clazz)
def examine_stream(stream):
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index 674bee1..7650795 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -59,24 +59,31 @@
*
* #include "section_list.h"
* ...
- * Privacy WindowState_state { 1, 9, NULL, LOCAL, NULL }; // first two integers are values for field id and proto type.
- * Privacy WindowState_child_windows { 3, 11, NULL, DEFAULT, NULL }; // reserved for WindowState_LIST
- * Privacy* WindowState_MSG_[] = {
+ * Privacy WindowState__state { 1, 9, NULL, LOCAL, NULL }; // first two integers are values for field id and proto type.
+ * Privacy WindowState__child_windows { 3, 11, NULL, UNSET, NULL }; // reserved for WindowState_LIST
+ * Privacy* WindowState__MSG__UNSET[] = {
* &WindowState_state,
* // display id is default, nothing is generated.
* &WindowState_child_windows,
* NULL // terminator of the array
* };
- * Privacy WindowState_my_window { 1, 11, WindowState_my_window_LIST, DEFAULT, NULL };
+ * Privacy WindowState__my_window { 1, 11, WindowState__MSG__UNSET, UNSET, NULL };
*
* createList() {
* ...
- * WindowState_child_windows.children = WindowState_my_window_LIST; // point to its own definition after the list is defined.
+ * WindowState_child_windows.children = WindowState__MSG_UNSET; // point to its own definition after the list is defined.
* ...
* }
*
* const Privacy** PRIVACY_POLICY_LIST = createList();
* const int PRIVACY_POLICY_COUNT = 1;
+ *
+ * Privacy Value Inheritance rules:
+ * 1. Both field and message can be tagged with DESTINATION: LOCAL(L), EXPLICIT(E), AUTOMATIC(A).
+ * 2. Primitives inherits containing message's tag unless defined explicitly.
+ * 3. Containing message's tag doesn't apply to message fields, even when unset (in this case, uses its default message tag).
+ * 4. Message field tag overrides its default message tag.
+ * 5. UNSET tag defaults to EXPLICIT.
*/
// The assignments will be called when constructs PRIVACY_POLICY_LIST, has to be global variable
@@ -164,14 +171,13 @@
return result;
}
-static string getFieldName(const FieldDescriptor* field) {
- return replaceAll(field->full_name(), '.', "__");
+static inline void printPrivacy(const string& name, const FieldDescriptor* field, const string& children,
+ const Destination dest, const string& patterns, const string& comments = "") {
+ printf("Privacy %s = { %d, %d, %s, %d, %s };%s\n", name.c_str(), field->number(), field->type(),
+ children.c_str(), dest, patterns.c_str(), comments.c_str());
}
-static string getMessageTypeName(const Descriptor* descriptor) {
- return replaceAll(descriptor->full_name(), '.', "_") + "_MSG_";
-}
-
+// Get Custom Options ================================================================================
static inline SectionFlags getSectionFlags(const FieldDescriptor* field) {
return field->options().GetExtension(section);
}
@@ -180,24 +186,64 @@
return field->options().GetExtension(privacy);
}
-static inline bool isDefaultField(const FieldDescriptor* field) {
- return getPrivacyFlags(field).dest() == PrivacyFlags::default_instance().dest();
+static inline PrivacyFlags getPrivacyFlags(const Descriptor* descriptor) {
+ return descriptor->options().GetExtension(msg_privacy);
}
-static bool isDefaultMessageImpl(const Descriptor* descriptor, set<string>* parents) {
- int N = descriptor->field_count();
+// Get Destinations ===================================================================================
+static inline Destination getMessageDest(const Descriptor* descriptor, const Destination overridden) {
+ return overridden != DEST_UNSET ? overridden : getPrivacyFlags(descriptor).dest();
+}
+
+// Returns field's own dest, when it is a message field, uses its message default tag if unset.
+static inline Destination getFieldDest(const FieldDescriptor* field) {
+ Destination fieldDest = getPrivacyFlags(field).dest();
+ return field->type() != FieldDescriptor::TYPE_MESSAGE ? fieldDest :
+ getMessageDest(field->message_type(), fieldDest);
+}
+
+// Get Names ===========================================================================================
+static inline string getFieldName(const FieldDescriptor* field) {
+ // replace . with double underscores to avoid name conflicts since fields use snake naming convention
+ return replaceAll(field->full_name(), '.', "__");
+}
+
+
+static inline string getMessageName(const Descriptor* descriptor, const Destination overridden) {
+ // replace . with one underscore since messages use camel naming convention
+ return replaceAll(descriptor->full_name(), '.', "_") + "__MSG__" +
+ to_string(getMessageDest(descriptor, overridden));
+}
+
+// IsDefault ============================================================================================
+// Returns true if a field is default. Default is defined as this field has same dest as its containing message.
+// For message fields, it only looks at its field tag and own default mesaage tag, doesn't recursively go deeper.
+static inline bool isDefaultField(const FieldDescriptor* field, const Destination containerDest) {
+ Destination fieldDest = getFieldDest(field);
+ if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
+ return fieldDest == containerDest || (fieldDest == DEST_UNSET);
+ } else {
+ return fieldDest == containerDest ||
+ (containerDest == DEST_UNSET && fieldDest == DEST_EXPLICIT) ||
+ (containerDest == DEST_EXPLICIT && fieldDest == DEST_UNSET);
+ }
+}
+
+static bool isDefaultMessageImpl(const Descriptor* descriptor, const Destination dest, set<string>* parents) {
+ const int N = descriptor->field_count();
+ const Destination messageDest = getMessageDest(descriptor, dest);
parents->insert(descriptor->full_name());
for (int i=0; i<N; ++i) {
const FieldDescriptor* field = descriptor->field(i);
- // look at if the current field is default or not, return false immediately
- if (!isDefaultField(field)) return false;
-
+ const Destination fieldDest = getFieldDest(field);
+ // If current field is not default, return false immediately
+ if (!isDefaultField(field, messageDest)) return false;
switch (field->type()) {
case FieldDescriptor::TYPE_MESSAGE:
// if self recursion, don't go deep.
if (parents->find(field->message_type()->full_name()) != parents->end()) break;
// if is a default message, just continue
- if (isDefaultMessageImpl(field->message_type(), parents)) break;
+ if (isDefaultMessageImpl(field->message_type(), fieldDest, parents)) break;
// sub message is not default, so this message is always not default
return false;
case FieldDescriptor::TYPE_STRING:
@@ -210,106 +256,118 @@
return true;
}
-static bool isDefaultMessage(const Descriptor* descriptor) {
+// Recursively look at if this message is default, meaning all its fields and sub-messages
+// can be described by the same dest.
+static bool isDefaultMessage(const Descriptor* descriptor, const Destination dest) {
set<string> parents;
- return isDefaultMessageImpl(descriptor, &parents);
+ return isDefaultMessageImpl(descriptor, dest, &parents);
}
-// This function is called for looking at privacy tags for a message type and recursively its sub-messages
-// It prints out each fields's privacy tags and a List of Privacy of the message itself (don't print default values)
-// Returns false if the descriptor doesn't have any non default privacy flags set, including its submessages
-static bool generatePrivacyFlags(const Descriptor* descriptor, map<string, bool> &msgNames, set<string>* parents) {
- bool hasDefaultFlags[descriptor->field_count()];
+// ===============================================================================================================
+static bool numberInOrder(const FieldDescriptor* f1, const FieldDescriptor* f2) {
+ return f1->number() < f2->number();
+}
- string messageTypeName = getMessageTypeName(descriptor);
- // if the message is already defined, skip it.
- if (msgNames.find(messageTypeName) != msgNames.end()) {
- bool hasDefault = msgNames[messageTypeName];
- return !hasDefault; // don't generate if it has default privacy.
+// field numbers are possibly out of order, sort them here.
+static vector<const FieldDescriptor*> sortFields(const Descriptor* descriptor) {
+ vector<const FieldDescriptor*> fields;
+ fields.reserve(descriptor->field_count());
+ for (int i=0; i<descriptor->field_count(); i++) {
+ fields.push_back(descriptor->field(i));
+ }
+ std::sort(fields.begin(), fields.end(), numberInOrder);
+ return fields;
+}
+
+// This function looks for privacy tags of a message type and recursively its sub-messages.
+// It generates Privacy objects for each non-default fields including non-default sub-messages.
+// And if the message has Privacy objects generated, it returns a list of them.
+// Returns false if the descriptor doesn't have any non default privacy flags set, including its submessages
+static bool generatePrivacyFlags(const Descriptor* descriptor, const Destination overridden,
+ map<string, bool> &variableNames, set<string>* parents) {
+ const string messageName = getMessageName(descriptor, overridden);
+ const Destination messageDest = getMessageDest(descriptor, overridden);
+
+ if (variableNames.find(messageName) != variableNames.end()) {
+ bool hasDefault = variableNames[messageName];
+ return !hasDefault; // if has default, then don't generate privacy flags.
}
// insert the message type name so sub-message will figure out if self-recursion occurs
- parents->insert(messageTypeName);
+ parents->insert(messageName);
- // iterate though its field and generate sub flags first
- for (int i=0; i<descriptor->field_count(); i++) {
- hasDefaultFlags[i] = true; // set default to true
-
- const FieldDescriptor* field = descriptor->field(i);
+ // sort fields based on number, iterate though them and generate sub flags first
+ vector<const FieldDescriptor*> fieldsInOrder = sortFields(descriptor);
+ bool hasDefaultFlags[fieldsInOrder.size()];
+ for (size_t i=0; i<fieldsInOrder.size(); i++) {
+ const FieldDescriptor* field = fieldsInOrder[i];
const string fieldName = getFieldName(field);
- // check if the same field name is already defined.
- if (msgNames.find(fieldName) != msgNames.end()) {
- hasDefaultFlags[i] = msgNames[fieldName];
- continue;
- };
+ const Destination fieldDest = getFieldDest(field);
- PrivacyFlags p = getPrivacyFlags(field);
+ if (variableNames.find(fieldName) != variableNames.end()) {
+ hasDefaultFlags[i] = variableNames[fieldName];
+ continue;
+ }
+ hasDefaultFlags[i] = isDefaultField(field, messageDest);
+
string fieldMessageName;
+ PrivacyFlags p = getPrivacyFlags(field);
switch (field->type()) {
case FieldDescriptor::TYPE_MESSAGE:
- fieldMessageName = getMessageTypeName(field->message_type());
+ fieldMessageName = getMessageName(field->message_type(), fieldDest);
if (parents->find(fieldMessageName) != parents->end()) { // Self-Recursion proto definition
- if (isDefaultField(field)) {
- hasDefaultFlags[i] = isDefaultMessage(field->message_type());
- } else {
- hasDefaultFlags[i] = false;
+ if (hasDefaultFlags[i]) {
+ hasDefaultFlags[i] = isDefaultMessage(field->message_type(), fieldDest);
}
if (!hasDefaultFlags[i]) {
- printf("Privacy %s = { %d, %d, NULL, %d, NULL }; // self recursion field of %s\n",
- fieldName.c_str(), field->number(), field->type(), p.dest(), fieldMessageName.c_str());
+ printPrivacy(fieldName, field, "NULL", fieldDest, "NULL",
+ " // self recursion field of " + fieldMessageName);
// generate the assignment and used to construct createList function later on.
gSelfRecursionAssignments.push_back(fieldName + ".children = " + fieldMessageName);
}
- break;
- } else if (generatePrivacyFlags(field->message_type(), msgNames, parents)) {
- printf("Privacy %s = { %d, %d, %s, %d, NULL };\n", fieldName.c_str(), field->number(),
- field->type(), fieldMessageName.c_str(), p.dest());
- } else if (isDefaultField(field)) {
- // don't create a new privacy if the value is default.
- break;
- } else {
- printf("Privacy %s = { %d, %d, NULL, %d, NULL };\n", fieldName.c_str(), field->number(),
- field->type(), p.dest());
+ } else if (generatePrivacyFlags(field->message_type(), p.dest(), variableNames, parents)) {
+ if (variableNames.find(fieldName) == variableNames.end()) {
+ printPrivacy(fieldName, field, fieldMessageName, fieldDest, "NULL");
+ }
+ hasDefaultFlags[i] = false;
+ } else if (!hasDefaultFlags[i]) {
+ printPrivacy(fieldName, field, "NULL", fieldDest, "NULL");
}
- hasDefaultFlags[i] = false;
break;
case FieldDescriptor::TYPE_STRING:
- if (isDefaultField(field) && p.patterns_size() == 0) break;
-
- printf("const char* %s_patterns[] = {\n", fieldName.c_str());
- for (int i=0; i<p.patterns_size(); i++) {
- // the generated string need to escape backslash as well, need to dup it here
- printf(" \"%s\",\n", replaceAll(p.patterns(i), '\\', "\\\\").c_str());
+ if (p.patterns_size() != 0) { // if patterns are specified
+ if (hasDefaultFlags[i]) break;
+ printf("const char* %s_patterns[] = {\n", fieldName.c_str());
+ for (int j=0; j<p.patterns_size(); j++) {
+ // generated string needs to escape backslash too, duplicate it to allow escape again.
+ printf(" \"%s\",\n", replaceAll(p.patterns(j), '\\', "\\\\").c_str());
+ }
+ printf(" NULL };\n");
+ printPrivacy(fieldName, field, "NULL", fieldDest, fieldName + "_patterns");
+ break;
}
- printf(" NULL };\n");
- printf("Privacy %s = { %d, %d, NULL, %d, %s_patterns };\n", fieldName.c_str(), field->number(),
- field->type(), p.dest(), fieldName.c_str());
- hasDefaultFlags[i] = false;
- break;
+ // else treat string field as primitive field and goes to default
default:
- if (isDefaultField(field)) break;
- printf("Privacy %s = { %d, %d, NULL, %d, NULL };\n", fieldName.c_str(), field->number(),
- field->type(), p.dest());
- hasDefaultFlags[i] = false;
+ if (!hasDefaultFlags[i]) printPrivacy(fieldName, field, "NULL", fieldDest, "NULL");
}
- // add the field name to message map, true means it has default flags
- msgNames[fieldName] = hasDefaultFlags[i];
+ // Don't generate a variable twice
+ if (!hasDefaultFlags[i]) variableNames[fieldName] = false;
}
bool allDefaults = true;
- for (int i=0; i<descriptor->field_count(); i++) {
+ for (size_t i=0; i<fieldsInOrder.size(); i++) {
allDefaults &= hasDefaultFlags[i];
}
- parents->erase(messageTypeName); // erase the message type name when exit the message.
- msgNames[messageTypeName] = allDefaults; // store the privacy tags of the message here to avoid overhead.
+ parents->erase(messageName); // erase the message type name when exit the message.
+ variableNames[messageName] = allDefaults; // store the privacy tags of the message here to avoid overhead.
if (allDefaults) return false;
emptyline();
int policyCount = 0;
- printf("Privacy* %s[] = {\n", messageTypeName.c_str());
- for (int i=0; i<descriptor->field_count(); i++) {
- const FieldDescriptor* field = descriptor->field(i);
+ printf("Privacy* %s[] = {\n", messageName.c_str());
+ for (size_t i=0; i<fieldsInOrder.size(); i++) {
+ const FieldDescriptor* field = fieldsInOrder[i];
if (hasDefaultFlags[i]) continue;
printf(" &%s,\n", getFieldName(field).c_str());
policyCount++;
@@ -359,29 +417,30 @@
// generates PRIVACY_POLICY_LIST
printf("// Generate PRIVACY_POLICY_LIST.\n\n");
- map<string, bool> messageNames;
+ map<string, bool> variableNames;
set<string> parents;
- bool skip[descriptor->field_count()];
+ vector<const FieldDescriptor*> fieldsInOrder = sortFields(descriptor);
+ bool skip[fieldsInOrder.size()];
+ const Destination incidentDest = getPrivacyFlags(descriptor).dest();
- for (int i=0; i<descriptor->field_count(); i++) {
- const FieldDescriptor* field = descriptor->field(i);
+ for (size_t i=0; i<fieldsInOrder.size(); i++) {
+ const FieldDescriptor* field = fieldsInOrder[i];
const string fieldName = getFieldName(field);
- PrivacyFlags p = getPrivacyFlags(field);
+ const Destination fieldDest = getFieldDest(field);
+ const string fieldMessageName = getMessageName(field->message_type(), fieldDest);
skip[i] = true;
if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
continue;
}
- // generate privacy flags for each field.
- if (generatePrivacyFlags(field->message_type(), messageNames, &parents)) {
- printf("Privacy %s { %d, %d, %s, %d, NULL };\n", fieldName.c_str(), field->number(),
- field->type(), getMessageTypeName(field->message_type()).c_str(), p.dest());
- } else if (isDefaultField(field)) {
+ // generate privacy flags for each section.
+ if (generatePrivacyFlags(field->message_type(), fieldDest, variableNames, &parents)) {
+ printPrivacy(fieldName, field, fieldMessageName, fieldDest, "NULL");
+ } else if (isDefaultField(field, incidentDest)) {
continue; // don't create a new privacy if the value is default.
} else {
- printf("Privacy %s { %d, %d, NULL, %d, NULL };\n", fieldName.c_str(), field->number(),
- field->type(), p.dest());
+ printPrivacy(fieldName, field, "NULL", fieldDest, "NULL");
}
skip[i] = false;
}
@@ -391,16 +450,16 @@
int policyCount = 0;
if (gSelfRecursionAssignments.empty()) {
printf("Privacy* privacyArray[] = {\n");
- for (int i=0; i<descriptor->field_count(); i++) {
+ for (size_t i=0; i<fieldsInOrder.size(); i++) {
if (skip[i]) continue;
- printf(" &%s,\n", getFieldName(descriptor->field(i)).c_str());
+ printf(" &%s,\n", getFieldName(fieldsInOrder[i]).c_str());
policyCount++;
}
printf("};\n\n");
printf("const Privacy** PRIVACY_POLICY_LIST = const_cast<const Privacy**>(privacyArray);\n\n");
printf("const int PRIVACY_POLICY_COUNT = %d;\n", policyCount);
} else {
- for (int i=0; i<descriptor->field_count(); i++) {
+ for (size_t i=0; i<fieldsInOrder.size(); i++) {
if (!skip[i]) policyCount++;
}
@@ -410,9 +469,9 @@
}
printf(" Privacy** privacyArray = (Privacy**)malloc(%d * sizeof(Privacy**));\n", policyCount);
policyCount = 0; // reset
- for (int i=0; i<descriptor->field_count(); i++) {
+ for (size_t i=0; i<fieldsInOrder.size(); i++) {
if (skip[i]) continue;
- printf(" privacyArray[%d] = &%s;\n", policyCount++, getFieldName(descriptor->field(i)).c_str());
+ printf(" privacyArray[%d] = &%s;\n", policyCount++, getFieldName(fieldsInOrder[i]).c_str());
}
printf(" return const_cast<const Privacy**>(privacyArray);\n");
printf("}\n\n");
diff --git a/tools/streaming_proto/Android.bp b/tools/streaming_proto/Android.bp
index dc5c14e..4e9391d 100644
--- a/tools/streaming_proto/Android.bp
+++ b/tools/streaming_proto/Android.bp
@@ -24,6 +24,10 @@
"stream_proto_utils.cpp",
"string_utils.cpp",
],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
shared_libs: ["libprotoc"],
}
diff --git a/tools/streaming_proto/stream_proto_utils.cpp b/tools/streaming_proto/stream_proto_utils.cpp
index e8f86bc..fb2d98d 100644
--- a/tools/streaming_proto/stream_proto_utils.cpp
+++ b/tools/streaming_proto/stream_proto_utils.cpp
@@ -13,8 +13,6 @@
// TODO: packed is not supported yet.
//
const uint64_t FIELD_COUNT_SHIFT = 40;
-const uint64_t FIELD_COUNT_MASK = 0x0fULL << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_UNKNOWN = 0;
const uint64_t FIELD_COUNT_SINGLE = 1ULL << FIELD_COUNT_SHIFT;
const uint64_t FIELD_COUNT_REPEATED = 2ULL << FIELD_COUNT_SHIFT;
const uint64_t FIELD_COUNT_PACKED = 5ULL << FIELD_COUNT_SHIFT;
diff --git a/wifi/java/android/net/wifi/BatchedScanResult.java b/wifi/java/android/net/wifi/BatchedScanResult.java
index 6d9f00f..c06543e 100644
--- a/wifi/java/android/net/wifi/BatchedScanResult.java
+++ b/wifi/java/android/net/wifi/BatchedScanResult.java
@@ -17,6 +17,7 @@
package android.net.wifi;
import android.os.Parcelable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import java.util.ArrayList;
@@ -29,6 +30,7 @@
* @removed
*/
@Deprecated
+@SystemApi
public class BatchedScanResult implements Parcelable {
private static final String TAG = "BatchedScanResult";
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index a9e1e9d..0dd964c 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -21,6 +21,7 @@
import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
@@ -163,12 +164,6 @@
void enableAggressiveHandover(int enabled);
int getAggressiveHandover();
- void setAllowScansWithTraffic(int enabled);
- int getAllowScansWithTraffic();
-
- boolean setEnableAutoJoinWhenAssociated(boolean enabled);
- boolean getEnableAutoJoinWhenAssociated();
-
void enableWifiConnectivityManager(boolean enabled);
WifiConnectionStatistics getConnectionStatistics();
@@ -184,5 +179,7 @@
void restoreBackupData(in byte[] data);
void restoreSupplicantBackupData(in byte[] supplicantData, in byte[] ipConfigData);
+
+ void startSubscriptionProvisioning(in OsuProvider provider, in IProvisioningCallback callback);
}
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index bf8fed1..3eb13ce 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -22,7 +22,6 @@
import android.net.NetworkUtils;
import android.text.TextUtils;
-import java.lang.Math;
import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.UnknownHostException;
@@ -126,143 +125,35 @@
public long rxSuccess;
/**
- * Average rate of lost transmitted packets, in units of packets per 5 seconds.
+ * Average rate of lost transmitted packets, in units of packets per second.
* @hide
*/
public double txBadRate;
/**
- * Average rate of transmitted retry packets, in units of packets per 5 seconds.
+ * Average rate of transmitted retry packets, in units of packets per second.
* @hide
*/
public double txRetriesRate;
/**
- * Average rate of successfully transmitted unicast packets, in units of packets per 5 seconds.
+ * Average rate of successfully transmitted unicast packets, in units of packets per second.
* @hide
*/
public double txSuccessRate;
/**
- * Average rate of received unicast data packets, in units of packets per 5 seconds.
+ * Average rate of received unicast data packets, in units of packets per second.
* @hide
*/
public double rxSuccessRate;
- private static final long RESET_TIME_STAMP = Long.MIN_VALUE;
- private static final long FILTER_TIME_CONSTANT = 3000;
- /**
- * This factor is used to adjust the rate output under the new algorithm
- * such that the result is comparable to the previous algorithm.
- * This actually converts from unit 'packets per second' to 'packets per 5 seconds'.
- */
- private static final long OUTPUT_SCALE_FACTOR = 5;
- private long mLastPacketCountUpdateTimeStamp;
-
- /**
- * @hide
- */
- public int badRssiCount;
-
- /**
- * @hide
- */
- public int linkStuckCount;
-
- /**
- * @hide
- */
- public int lowRssiCount;
-
/**
* @hide
*/
public int score;
/**
- * @hide
+ * Flag indicating that AP has hinted that upstream connection is metered,
+ * and sensitive to heavy data transfers.
*/
- public void updatePacketRates(WifiLinkLayerStats stats, long timeStamp) {
- if (stats != null) {
- long txgood = stats.txmpdu_be + stats.txmpdu_bk + stats.txmpdu_vi + stats.txmpdu_vo;
- long txretries = stats.retries_be + stats.retries_bk
- + stats.retries_vi + stats.retries_vo;
- long rxgood = stats.rxmpdu_be + stats.rxmpdu_bk + stats.rxmpdu_vi + stats.rxmpdu_vo;
- long txbad = stats.lostmpdu_be + stats.lostmpdu_bk
- + stats.lostmpdu_vi + stats.lostmpdu_vo;
-
- if (mLastPacketCountUpdateTimeStamp != RESET_TIME_STAMP
- && mLastPacketCountUpdateTimeStamp < timeStamp
- && txBad <= txbad
- && txSuccess <= txgood
- && rxSuccess <= rxgood
- && txRetries <= txretries) {
- long timeDelta = timeStamp - mLastPacketCountUpdateTimeStamp;
- double lastSampleWeight = Math.exp(-1.0 * timeDelta / FILTER_TIME_CONSTANT);
- double currentSampleWeight = 1.0 - lastSampleWeight;
-
- txBadRate = txBadRate * lastSampleWeight
- + (txbad - txBad) * OUTPUT_SCALE_FACTOR * 1000 / timeDelta
- * currentSampleWeight;
- txSuccessRate = txSuccessRate * lastSampleWeight
- + (txgood - txSuccess) * OUTPUT_SCALE_FACTOR * 1000 / timeDelta
- * currentSampleWeight;
- rxSuccessRate = rxSuccessRate * lastSampleWeight
- + (rxgood - rxSuccess) * OUTPUT_SCALE_FACTOR * 1000 / timeDelta
- * currentSampleWeight;
- txRetriesRate = txRetriesRate * lastSampleWeight
- + (txretries - txRetries) * OUTPUT_SCALE_FACTOR * 1000/ timeDelta
- * currentSampleWeight;
- } else {
- txBadRate = 0;
- txSuccessRate = 0;
- rxSuccessRate = 0;
- txRetriesRate = 0;
- }
- txBad = txbad;
- txSuccess = txgood;
- rxSuccess = rxgood;
- txRetries = txretries;
- mLastPacketCountUpdateTimeStamp = timeStamp;
- } else {
- txBad = 0;
- txSuccess = 0;
- rxSuccess = 0;
- txRetries = 0;
- txBadRate = 0;
- txSuccessRate = 0;
- rxSuccessRate = 0;
- txRetriesRate = 0;
- mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
- }
- }
-
-
- /**
- * This function is less powerful and used if the WifiLinkLayerStats API is not implemented
- * at the Wifi HAL
- * @hide
- */
- public void updatePacketRates(long txPackets, long rxPackets) {
- //paranoia
- txBad = 0;
- txRetries = 0;
- txBadRate = 0;
- txRetriesRate = 0;
- if (txSuccess <= txPackets && rxSuccess <= rxPackets) {
- txSuccessRate = (txSuccessRate * 0.5)
- + ((double) (txPackets - txSuccess) * 0.5);
- rxSuccessRate = (rxSuccessRate * 0.5)
- + ((double) (rxPackets - rxSuccess) * 0.5);
- } else {
- txBadRate = 0;
- txRetriesRate = 0;
- }
- txSuccess = txPackets;
- rxSuccess = rxPackets;
- }
-
- /**
- * Flag indicating that AP has hinted that upstream connection is metered,
- * and sensitive to heavy data transfers.
- */
private boolean mMeteredHint;
/** @hide */
@@ -274,7 +165,6 @@
mRssi = INVALID_RSSI;
mLinkSpeed = -1;
mFrequency = -1;
- mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
}
/** @hide */
@@ -296,11 +186,7 @@
txSuccessRate = 0;
rxSuccessRate = 0;
txRetriesRate = 0;
- lowRssiCount = 0;
- badRssiCount = 0;
- linkStuckCount = 0;
score = 0;
- mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
}
/**
@@ -328,12 +214,7 @@
txRetriesRate = source.txRetriesRate;
txSuccessRate = source.txSuccessRate;
rxSuccessRate = source.rxSuccessRate;
- mLastPacketCountUpdateTimeStamp =
- source.mLastPacketCountUpdateTimeStamp;
score = source.score;
- badRssiCount = source.badRssiCount;
- lowRssiCount = source.lowRssiCount;
- linkStuckCount = source.linkStuckCount;
}
}
@@ -452,22 +333,6 @@
}
/**
- * @hide
- * This returns txSuccessRate in packets per second.
- */
- public double getTxSuccessRatePps() {
- return txSuccessRate / OUTPUT_SCALE_FACTOR;
- }
-
- /**
- * @hide
- * This returns rxSuccessRate in packets per second.
- */
- public double getRxSuccessRatePps() {
- return rxSuccessRate / OUTPUT_SCALE_FACTOR;
- }
-
- /**
* Record the MAC address of the WLAN interface
* @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form
* @hide
@@ -658,8 +523,6 @@
dest.writeDouble(txRetriesRate);
dest.writeDouble(txBadRate);
dest.writeDouble(rxSuccessRate);
- dest.writeInt(badRssiCount);
- dest.writeInt(lowRssiCount);
mSupplicantState.writeToParcel(dest, flags);
}
@@ -689,8 +552,6 @@
info.txRetriesRate = in.readDouble();
info.txBadRate = in.readDouble();
info.rxSuccessRate = in.readDouble();
- info.badRssiCount = in.readInt();
- info.lowRssiCount = in.readInt();
info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in);
return info;
}
diff --git a/wifi/java/android/net/wifi/WifiLinkLayerStats.java b/wifi/java/android/net/wifi/WifiLinkLayerStats.java
deleted file mode 100644
index edd400b..0000000
--- a/wifi/java/android/net/wifi/WifiLinkLayerStats.java
+++ /dev/null
@@ -1,211 +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 android.net.wifi;
-
-import android.os.Parcelable;
-import android.os.Parcel;
-
-import java.util.Arrays;
-
-/**
- * A class representing link layer statistics collected over a Wifi Interface.
- */
-/** {@hide} */
-public class WifiLinkLayerStats implements Parcelable {
- private static final String TAG = "WifiLinkLayerStats";
-
- /**
- * The current status of this network configuration entry.
- * @see Status
- */
- /** {@hide} */
- public int status;
-
- /**
- * The network's SSID. Can either be an ASCII string,
- * which must be enclosed in double quotation marks
- * (e.g., {@code "MyNetwork"}, or a string of
- * hex digits,which are not enclosed in quotes
- * (e.g., {@code 01a243f405}).
- */
- /** {@hide} */
- public String SSID;
- /**
- * When set. this is the BSSID the radio is currently associated with.
- * The value is a string in the format of an Ethernet MAC address, e.g.,
- * <code>XX:XX:XX:XX:XX:XX</code> where each <code>X</code> is a hex digit.
- */
- /** {@hide} */
- public String BSSID;
-
- /* number beacons received from our own AP */
- /** {@hide} */
- public int beacon_rx;
-
- /* RSSI taken on management frames */
- /** {@hide} */
- public int rssi_mgmt;
-
- /* packets counters */
- /** {@hide} */
- /* WME Best Effort Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries)*/
- public long rxmpdu_be;
- /** {@hide} */
- public long txmpdu_be;
- /** {@hide} */
- public long lostmpdu_be;
- /** {@hide} */
- public long retries_be;
- /** {@hide} */
- /* WME Background Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries) */
- public long rxmpdu_bk;
- /** {@hide} */
- public long txmpdu_bk;
- /** {@hide} */
- public long lostmpdu_bk;
- /** {@hide} */
- public long retries_bk;
- /** {@hide} */
- /* WME Video Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries) */
- public long rxmpdu_vi;
- /** {@hide} */
- public long txmpdu_vi;
- /** {@hide} */
- public long lostmpdu_vi;
- /** {@hide} */
- public long retries_vi;
- /** {@hide} */
- /* WME Voice Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries) */
- public long rxmpdu_vo;
- /** {@hide} */
- public long txmpdu_vo;
- /** {@hide} */
- public long lostmpdu_vo;
- /** {@hide} */
- public long retries_vo;
-
- /** {@hide} */
- public int on_time;
- /** {@hide} */
- public int tx_time;
- /** {@hide} */
- public int[] tx_time_per_level;
- /** {@hide} */
- public int rx_time;
- /** {@hide} */
- public int on_time_scan;
-
- /** {@hide} */
- public WifiLinkLayerStats() {
- }
-
- @Override
- /** {@hide} */
- public String toString() {
- StringBuilder sbuf = new StringBuilder();
- sbuf.append(" WifiLinkLayerStats: ").append('\n');
-
- if (this.SSID != null) {
- sbuf.append(" SSID: ").append(this.SSID).append('\n');
- }
- if (this.BSSID != null) {
- sbuf.append(" BSSID: ").append(this.BSSID).append('\n');
- }
-
- sbuf.append(" my bss beacon rx: ").append(Integer.toString(this.beacon_rx)).append('\n');
- sbuf.append(" RSSI mgmt: ").append(Integer.toString(this.rssi_mgmt)).append('\n');
- sbuf.append(" BE : ").append(" rx=").append(Long.toString(this.rxmpdu_be))
- .append(" tx=").append(Long.toString(this.txmpdu_be))
- .append(" lost=").append(Long.toString(this.lostmpdu_be))
- .append(" retries=").append(Long.toString(this.retries_be)).append('\n');
- sbuf.append(" BK : ").append(" rx=").append(Long.toString(this.rxmpdu_bk))
- .append(" tx=").append(Long.toString(this.txmpdu_bk))
- .append(" lost=").append(Long.toString(this.lostmpdu_bk))
- .append(" retries=").append(Long.toString(this.retries_bk)).append('\n');
- sbuf.append(" VI : ").append(" rx=").append(Long.toString(this.rxmpdu_vi))
- .append(" tx=").append(Long.toString(this.txmpdu_vi))
- .append(" lost=").append(Long.toString(this.lostmpdu_vi))
- .append(" retries=").append(Long.toString(this.retries_vi)).append('\n');
- sbuf.append(" VO : ").append(" rx=").append(Long.toString(this.rxmpdu_vo))
- .append(" tx=").append(Long.toString(this.txmpdu_vo))
- .append(" lost=").append(Long.toString(this.lostmpdu_vo))
- .append(" retries=").append(Long.toString(this.retries_vo)).append('\n');
- sbuf.append(" on_time : ").append(Integer.toString(this.on_time))
- .append(" rx_time=").append(Integer.toString(this.rx_time))
- .append(" scan_time=").append(Integer.toString(this.on_time_scan)).append('\n')
- .append(" tx_time=").append(Integer.toString(this.tx_time))
- .append(" tx_time_per_level=" + Arrays.toString(tx_time_per_level));
- return sbuf.toString();
- }
-
- /** Implement the Parcelable interface {@hide} */
- public int describeContents() {
- return 0;
- }
-
- /** {@hide} */
- public String getPrintableSsid() {
- if (SSID == null) return "";
- final int length = SSID.length();
- if (length > 2 && (SSID.charAt(0) == '"') && SSID.charAt(length - 1) == '"') {
- return SSID.substring(1, length - 1);
- }
-
- /** The ascii-encoded string format is P"<ascii-encoded-string>"
- * The decoding is implemented in the supplicant for a newly configured
- * network.
- */
- if (length > 3 && (SSID.charAt(0) == 'P') && (SSID.charAt(1) == '"') &&
- (SSID.charAt(length-1) == '"')) {
- WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded(
- SSID.substring(2, length - 1));
- return wifiSsid.toString();
- }
- return SSID;
- }
-
- /** Implement the Parcelable interface {@hide} */
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(SSID);
- dest.writeString(BSSID);
- dest.writeInt(on_time);
- dest.writeInt(tx_time);
- dest.writeIntArray(tx_time_per_level);
- dest.writeInt(rx_time);
- dest.writeInt(on_time_scan);
- }
-
- /** Implement the Parcelable interface {@hide} */
- public static final Creator<WifiLinkLayerStats> CREATOR =
- new Creator<WifiLinkLayerStats>() {
- public WifiLinkLayerStats createFromParcel(Parcel in) {
- WifiLinkLayerStats stats = new WifiLinkLayerStats();
- stats.SSID = in.readString();
- stats.BSSID = in.readString();
- stats.on_time = in.readInt();
- stats.tx_time = in.readInt();
- stats.tx_time_per_level = in.createIntArray();
- stats.rx_time = in.readInt();
- stats.on_time_scan = in.readInt();
- return stats;
- };
- public WifiLinkLayerStats[] newArray(int size) {
- return new WifiLinkLayerStats[size];
- }
-
- };
-}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 183cf0d..a158d94 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -33,6 +33,8 @@
import android.net.NetworkRequest;
import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.hotspot2.IProvisioningCallback;
+import android.net.wifi.hotspot2.ProvisioningCallback;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -3486,27 +3488,23 @@
}
/**
- * Set setting for allowing Scans when traffic is ongoing.
+ * Deprecated
+ * Does nothing
* @hide
+ * @deprecated
*/
public void setAllowScansWithTraffic(int enabled) {
- try {
- mService.setAllowScansWithTraffic(enabled);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return;
}
/**
- * Get setting for allowing Scans when traffic is ongoing.
+ * Deprecated
+ * returns value for 'disabled'
* @hide
+ * @deprecated
*/
public int getAllowScansWithTraffic() {
- try {
- return mService.getAllowScansWithTraffic();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return 0;
}
/**
@@ -3536,29 +3534,23 @@
}
/**
- * Framework layer autojoin enable/disable when device is associated
- * this will enable/disable autojoin scan and switch network when connected
- * @return true -- if set successful false -- if set failed
+ * Deprecated
+ * returns false
* @hide
+ * @deprecated
*/
public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
- try {
- return mService.setEnableAutoJoinWhenAssociated(enabled);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return false;
}
/**
- * Get setting for Framework layer autojoin enable status
+ * Deprecated
+ * returns false
* @hide
+ * @deprecated
*/
public boolean getEnableAutoJoinWhenAssociated() {
- try {
- return mService.getEnableAutoJoinWhenAssociated();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return false;
}
/**
@@ -3610,4 +3602,45 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Start subscription provisioning flow
+ * @param provider {@link OsuProvider} to provision with
+ * @param callback {@link ProvisioningCallback} for updates regarding provisioning flow
+ * @hide
+ */
+ public void startSubscriptionProvisioning(OsuProvider provider, ProvisioningCallback callback,
+ @Nullable Handler handler) {
+ Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
+ try {
+ mService.startSubscriptionProvisioning(provider,
+ new ProvisioningCallbackProxy(looper, callback));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private static class ProvisioningCallbackProxy extends IProvisioningCallback.Stub {
+ private final Handler mHandler;
+ private final ProvisioningCallback mCallback;
+
+ ProvisioningCallbackProxy(Looper looper, ProvisioningCallback callback) {
+ mHandler = new Handler(looper);
+ mCallback = callback;
+ }
+
+ @Override
+ public void onProvisioningStatus(int status) {
+ mHandler.post(() -> {
+ mCallback.onProvisioningStatus(status);
+ });
+ }
+
+ @Override
+ public void onProvisioningFailure(int status) {
+ mHandler.post(() -> {
+ mCallback.onProvisioningFailure(status);
+ });
+ }
+ }
}
diff --git a/wifi/java/android/net/wifi/aware/PeerHandle.java b/wifi/java/android/net/wifi/aware/PeerHandle.java
index 1b0aba1..b525212 100644
--- a/wifi/java/android/net/wifi/aware/PeerHandle.java
+++ b/wifi/java/android/net/wifi/aware/PeerHandle.java
@@ -33,7 +33,6 @@
/** @hide */
public int peerId;
- /** @hide RTT_API */
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -47,7 +46,6 @@
return peerId == ((PeerHandle) o).peerId;
}
- /** @hide RTT_API */
@Override
public int hashCode() {
return peerId;
diff --git a/core/java/android/service/autofill/IAuthenticationCallback.aidl b/wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl
similarity index 62%
copy from core/java/android/service/autofill/IAuthenticationCallback.aidl
copy to wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl
index 36b989d..c2cb16a 100644
--- a/core/java/android/service/autofill/IAuthenticationCallback.aidl
+++ b/wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl
@@ -14,18 +14,23 @@
* limitations under the License.
*/
-package android.view.autofill;
-
-import android.view.autofill.Dataset;
-import android.service.autofill.FillResponse;
+package android.net.wifi.hotspot2;
/**
- * Callback for delivering authentication result.
+ * Interface for Provisioning callback.
*
- * {@hide}
+ * @hide
*/
-interface IAutoFillAuthCallback {
- void onSuccessForDataset(in Dataset dataset);
- void onSuccessForFillResponse(in FillResponse response);
- void onFailure(CharSequence message);
+oneway interface IProvisioningCallback
+{
+ /**
+ * Service to manager callback providing failure notification
+ */
+ void onProvisioningFailure(int status);
+
+ /**
+ * Service to manager callback providing Provisioning status
+ */
+ void onProvisioningStatus(int status);
}
+
diff --git a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
new file mode 100644
index 0000000..8b86cdd
--- /dev/null
+++ b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
@@ -0,0 +1,59 @@
+/*
+ * 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 android.net.wifi.hotspot2;
+
+import android.os.Handler;
+
+/**
+ * Base class for provisioning callbacks. Should be extended by applications and set when calling
+ * {@link WifiManager#startSubscriptionProvisiong(OsuProvider, ProvisioningCallback, Handler)}.
+ *
+ * @hide
+ */
+public abstract class ProvisioningCallback {
+
+ /**
+ * The reason code for Provisioning Failure due to connection failure to OSU AP.
+ * @hide
+ */
+ public static final int OSU_FAILURE_AP_CONNECTION = 1;
+
+ /**
+ * The status code for Provisioning flow to indicate connecting to OSU AP
+ * @hide
+ */
+ public static final int OSU_STATUS_AP_CONNECTING = 1;
+
+ /**
+ * The status code for Provisioning flow to indicate connected to OSU AP
+ * @hide
+ */
+ public static final int OSU_STATUS_AP_CONNECTED = 2;
+
+ /**
+ * Provisioning status for OSU failure
+ * @param status indicates error condition
+ */
+ public abstract void onProvisioningFailure(int status);
+
+ /**
+ * Provisioning status when OSU is in progress
+ * @param status indicates status of OSU flow
+ */
+ public abstract void onProvisioningStatus(int status);
+}
+
diff --git a/wifi/java/android/net/wifi/rtt/RangingRequest.java b/wifi/java/android/net/wifi/rtt/RangingRequest.java
index a396281..b4e3097 100644
--- a/wifi/java/android/net/wifi/rtt/RangingRequest.java
+++ b/wifi/java/android/net/wifi/rtt/RangingRequest.java
@@ -16,6 +16,8 @@
package android.net.wifi.rtt;
+import android.annotation.NonNull;
+import android.net.MacAddress;
import android.net.wifi.ScanResult;
import android.net.wifi.aware.AttachCallback;
import android.net.wifi.aware.DiscoverySessionCallback;
@@ -25,14 +27,9 @@
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
-import android.text.TextUtils;
-
-import libcore.util.HexEncoding;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
-import java.util.Objects;
import java.util.StringJoiner;
/**
@@ -63,10 +60,10 @@
}
/** @hide */
- public final List<RttPeer> mRttPeers;
+ public final List<ResponderConfig> mRttPeers;
/** @hide */
- private RangingRequest(List<RttPeer> rttPeers) {
+ private RangingRequest(List<ResponderConfig> rttPeers) {
mRttPeers = rttPeers;
}
@@ -95,9 +92,9 @@
/** @hide */
@Override
public String toString() {
- StringJoiner sj = new StringJoiner(", ", "RangingRequest: mRttPeers=[", ",");
- for (RttPeer rp : mRttPeers) {
- sj.add(rp.toString());
+ StringJoiner sj = new StringJoiner(", ", "RangingRequest: mRttPeers=[", "]");
+ for (ResponderConfig rc : mRttPeers) {
+ sj.add(rc.toString());
}
return sj.toString();
}
@@ -109,26 +106,9 @@
"Ranging to too many peers requested. Use getMaxPeers() API to get limit.");
}
- for (RttPeer peer: mRttPeers) {
- if (peer instanceof RttPeerAp) {
- RttPeerAp apPeer = (RttPeerAp) peer;
- if (apPeer.scanResult == null || apPeer.scanResult.BSSID == null) {
- throw new IllegalArgumentException("Invalid AP peer specification");
- }
- } else if (peer instanceof RttPeerAware) {
- if (!awareSupported) {
- throw new IllegalArgumentException(
- "Request contains Aware peers - but Aware isn't supported on this "
- + "device");
- }
-
- RttPeerAware awarePeer = (RttPeerAware) peer;
- if (awarePeer.peerMacAddress == null && awarePeer.peerHandle == null) {
- throw new IllegalArgumentException("Invalid Aware peer specification");
- }
- } else {
- throw new IllegalArgumentException(
- "Request contains unknown peer specification types");
+ for (ResponderConfig peer: mRttPeers) {
+ if (!peer.isValid(awareSupported)) {
+ throw new IllegalArgumentException("Invalid Responder specification");
}
}
}
@@ -137,35 +117,34 @@
* Builder class used to construct {@link RangingRequest} objects.
*/
public static final class Builder {
- private List<RttPeer> mRttPeers = new ArrayList<>();
+ private List<ResponderConfig> mRttPeers = new ArrayList<>();
/**
* Add the device specified by the {@link ScanResult} to the list of devices with
- * which to measure range. The total number of results added to a request cannot exceed the
+ * which to measure range. The total number of peers added to a request cannot exceed the
* limit specified by {@link #getMaxPeers()}.
*
* @param apInfo Information of an Access Point (AP) obtained in a Scan Result.
* @return The builder to facilitate chaining
* {@code builder.setXXX(..).setXXX(..)}.
*/
- public Builder addAccessPoint(ScanResult apInfo) {
+ public Builder addAccessPoint(@NonNull ScanResult apInfo) {
if (apInfo == null) {
throw new IllegalArgumentException("Null ScanResult!");
}
- mRttPeers.add(new RttPeerAp(apInfo));
- return this;
+ return addResponder(ResponderConfig.fromScanResult(apInfo));
}
/**
* Add the devices specified by the {@link ScanResult}s to the list of devices with
- * which to measure range. The total number of results added to a request cannot exceed the
+ * which to measure range. The total number of peers added to a request cannot exceed the
* limit specified by {@link #getMaxPeers()}.
*
* @param apInfos Information of an Access Points (APs) obtained in a Scan Result.
* @return The builder to facilitate chaining
* {@code builder.setXXX(..).setXXX(..)}.
*/
- public Builder addAccessPoints(List<ScanResult> apInfos) {
+ public Builder addAccessPoints(@NonNull List<ScanResult> apInfos) {
if (apInfos == null) {
throw new IllegalArgumentException("Null list of ScanResults!");
}
@@ -190,9 +169,12 @@
* @param peerMacAddress The MAC address of the Wi-Fi Aware peer.
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
*/
- public Builder addWifiAwarePeer(byte[] peerMacAddress) {
- mRttPeers.add(new RttPeerAware(peerMacAddress));
- return this;
+ public Builder addWifiAwarePeer(@NonNull MacAddress peerMacAddress) {
+ if (peerMacAddress == null) {
+ throw new IllegalArgumentException("Null peer MAC address");
+ }
+ return addResponder(
+ ResponderConfig.fromWifiAwarePeerMacAddressWithDefaults(peerMacAddress));
}
/**
@@ -208,8 +190,30 @@
* @param peerHandle The peer handler of the peer Wi-Fi Aware device.
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
*/
- public Builder addWifiAwarePeer(PeerHandle peerHandle) {
- mRttPeers.add(new RttPeerAware(peerHandle));
+ public Builder addWifiAwarePeer(@NonNull PeerHandle peerHandle) {
+ if (peerHandle == null) {
+ throw new IllegalArgumentException("Null peer handler (identifier)");
+ }
+
+ return addResponder(ResponderConfig.fromWifiAwarePeerHandleWithDefaults(peerHandle));
+ }
+
+ /*
+ * Add the Responder device specified by the {@link ResponderConfig} to the list of devices
+ * with which to measure range. The total number of peers added to the request cannot exceed
+ * the limit specified by {@link #getMaxPeers()}.
+ *
+ * @param responder Information on the RTT Responder.
+ * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+ *
+ * @hide (SystemApi)
+ */
+ public Builder addResponder(@NonNull ResponderConfig responder) {
+ if (responder == null) {
+ throw new IllegalArgumentException("Null Responder!");
+ }
+
+ mRttPeers.add(responder);
return this;
}
@@ -241,152 +245,4 @@
public int hashCode() {
return mRttPeers.hashCode();
}
-
- /** @hide */
- public interface RttPeer {
- // empty (marker interface)
- }
-
- /** @hide */
- public static class RttPeerAp implements RttPeer, Parcelable {
- public final ScanResult scanResult;
-
- public RttPeerAp(ScanResult scanResult) {
- this.scanResult = scanResult;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- scanResult.writeToParcel(dest, flags);
- }
-
- public static final Creator<RttPeerAp> CREATOR = new Creator<RttPeerAp>() {
- @Override
- public RttPeerAp[] newArray(int size) {
- return new RttPeerAp[size];
- }
-
- @Override
- public RttPeerAp createFromParcel(Parcel in) {
- return new RttPeerAp(ScanResult.CREATOR.createFromParcel(in));
- }
- };
-
- @Override
- public String toString() {
- return new StringBuilder("RttPeerAp: scanResult=").append(
- scanResult.toString()).toString();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
-
- if (!(o instanceof RttPeerAp)) {
- return false;
- }
-
- RttPeerAp lhs = (RttPeerAp) o;
-
- // Note: the only thing which matters for the request identity is the BSSID of the AP
- return TextUtils.equals(scanResult.BSSID, lhs.scanResult.BSSID);
- }
-
- @Override
- public int hashCode() {
- return scanResult.hashCode();
- }
- }
-
- /** @hide */
- public static class RttPeerAware implements RttPeer, Parcelable {
- public PeerHandle peerHandle;
- public byte[] peerMacAddress;
-
- public RttPeerAware(PeerHandle peerHandle) {
- if (peerHandle == null) {
- throw new IllegalArgumentException("Null peerHandle");
- }
- this.peerHandle = peerHandle;
- peerMacAddress = null;
- }
-
- public RttPeerAware(byte[] peerMacAddress) {
- if (peerMacAddress == null) {
- throw new IllegalArgumentException("Null peerMacAddress");
- }
-
- this.peerMacAddress = peerMacAddress;
- peerHandle = null;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- if (peerHandle == null) {
- dest.writeBoolean(false);
- dest.writeByteArray(peerMacAddress);
- } else {
- dest.writeBoolean(true);
- dest.writeInt(peerHandle.peerId);
- }
- }
-
- public static final Creator<RttPeerAware> CREATOR = new Creator<RttPeerAware>() {
- @Override
- public RttPeerAware[] newArray(int size) {
- return new RttPeerAware[size];
- }
-
- @Override
- public RttPeerAware createFromParcel(Parcel in) {
- boolean peerHandleAvail = in.readBoolean();
- if (peerHandleAvail) {
- return new RttPeerAware(new PeerHandle(in.readInt()));
- } else {
- return new RttPeerAware(in.createByteArray());
- }
- }
- };
-
- @Override
- public String toString() {
- return new StringBuilder("RttPeerAware: peerHandle=").append(
- peerHandle == null ? "<null>" : Integer.toString(peerHandle.peerId)).append(
- ", peerMacAddress=").append(peerMacAddress == null ? "<null>"
- : new String(HexEncoding.encode(peerMacAddress))).toString();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
-
- if (!(o instanceof RttPeerAware)) {
- return false;
- }
-
- RttPeerAware lhs = (RttPeerAware) o;
-
- return Objects.equals(peerHandle, lhs.peerHandle) && Arrays.equals(peerMacAddress,
- lhs.peerMacAddress);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(peerHandle.peerId, peerMacAddress);
- }
- }
}
diff --git a/wifi/java/android/net/wifi/rtt/RangingResult.java b/wifi/java/android/net/wifi/rtt/RangingResult.java
index 93e52ae..a380fae 100644
--- a/wifi/java/android/net/wifi/rtt/RangingResult.java
+++ b/wifi/java/android/net/wifi/rtt/RangingResult.java
@@ -17,16 +17,15 @@
package android.net.wifi.rtt;
import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.net.MacAddress;
import android.net.wifi.aware.PeerHandle;
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
-import libcore.util.HexEncoding;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -62,7 +61,7 @@
public static final int STATUS_FAIL = 1;
private final int mStatus;
- private final byte[] mMac;
+ private final MacAddress mMac;
private final PeerHandle mPeerHandle;
private final int mDistanceMm;
private final int mDistanceStdDevMm;
@@ -70,7 +69,7 @@
private final long mTimestamp;
/** @hide */
- public RangingResult(@RangeResultStatus int status, byte[] mac, int distanceMm,
+ public RangingResult(@RangeResultStatus int status, @NonNull MacAddress mac, int distanceMm,
int distanceStdDevMm, int rssi, long timestamp) {
mStatus = status;
mMac = mac;
@@ -109,7 +108,7 @@
* Will return a {@code null} for results corresponding to requests issued using a {@code
* PeerHandle}, i.e. using the {@link RangingRequest.Builder#addWifiAwarePeer(PeerHandle)} API.
*/
- public byte[] getMacAddress() {
+ public MacAddress getMacAddress() {
return mMac;
}
@@ -193,7 +192,12 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mStatus);
- dest.writeByteArray(mMac);
+ if (mMac == null) {
+ dest.writeBoolean(false);
+ } else {
+ dest.writeBoolean(true);
+ mMac.writeToParcel(dest, flags);
+ }
if (mPeerHandle == null) {
dest.writeBoolean(false);
} else {
@@ -216,7 +220,11 @@
@Override
public RangingResult createFromParcel(Parcel in) {
int status = in.readInt();
- byte[] mac = in.createByteArray();
+ boolean macAddressPresent = in.readBoolean();
+ MacAddress mac = null;
+ if (macAddressPresent) {
+ mac = MacAddress.CREATOR.createFromParcel(in);
+ }
boolean peerHandlePresent = in.readBoolean();
PeerHandle peerHandle = null;
if (peerHandlePresent) {
@@ -240,11 +248,11 @@
@Override
public String toString() {
return new StringBuilder("RangingResult: [status=").append(mStatus).append(", mac=").append(
- mMac == null ? "<null>" : new String(HexEncoding.encodeToString(mMac))).append(
- ", peerHandle=").append(mPeerHandle == null ? "<null>" : mPeerHandle.peerId).append(
- ", distanceMm=").append(mDistanceMm).append(", distanceStdDevMm=").append(
- mDistanceStdDevMm).append(", rssi=").append(mRssi).append(", timestamp=").append(
- mTimestamp).append("]").toString();
+ mMac).append(", peerHandle=").append(
+ mPeerHandle == null ? "<null>" : mPeerHandle.peerId).append(", distanceMm=").append(
+ mDistanceMm).append(", distanceStdDevMm=").append(mDistanceStdDevMm).append(
+ ", rssi=").append(mRssi).append(", timestamp=").append(mTimestamp).append(
+ "]").toString();
}
@Override
@@ -259,7 +267,7 @@
RangingResult lhs = (RangingResult) o;
- return mStatus == lhs.mStatus && Arrays.equals(mMac, lhs.mMac) && Objects.equals(
+ return mStatus == lhs.mStatus && Objects.equals(mMac, lhs.mMac) && Objects.equals(
mPeerHandle, lhs.mPeerHandle) && mDistanceMm == lhs.mDistanceMm
&& mDistanceStdDevMm == lhs.mDistanceStdDevMm && mRssi == lhs.mRssi
&& mTimestamp == lhs.mTimestamp;
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/wifi/java/android/net/wifi/rtt/ResponderConfig.aidl
similarity index 71%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to wifi/java/android/net/wifi/rtt/ResponderConfig.aidl
index 4ccdea5..fd3988a 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/wifi/java/android/net/wifi/rtt/ResponderConfig.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,11 +14,6 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+package android.net.wifi.rtt;
-import android.telephony.SubscriptionInfo;
-
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
-}
-
+parcelable ResponderConfig;
diff --git a/wifi/java/android/net/wifi/rtt/ResponderConfig.java b/wifi/java/android/net/wifi/rtt/ResponderConfig.java
new file mode 100644
index 0000000..8be7782
--- /dev/null
+++ b/wifi/java/android/net/wifi/rtt/ResponderConfig.java
@@ -0,0 +1,436 @@
+/*
+ * 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 android.net.wifi.rtt;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.net.MacAddress;
+import android.net.wifi.ScanResult;
+import android.net.wifi.aware.PeerHandle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Defines the configuration of an IEEE 802.11mc Responder. The Responder may be an Access Point
+ * (AP), a Wi-Fi Aware device, or a manually configured Responder.
+ * <p>
+ * A Responder configuration may be constructed from a {@link ScanResult} or manually (with the
+ * data obtained out-of-band from a peer).
+ *
+ * @hide (@SystemApi)
+ */
+public class ResponderConfig implements Parcelable {
+ private static final int AWARE_BAND_2_DISCOVERY_CHANNEL = 2437;
+
+ /** @hide */
+ @IntDef({RESPONDER_AP, RESPONDER_STA, RESPONDER_P2P_GO, RESPONDER_P2P_CLIENT, RESPONDER_AWARE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ResponderType {
+ }
+
+ /**
+ * Responder is an AP.
+ */
+ public static final int RESPONDER_AP = 0;
+ /**
+ * Responder is a STA.
+ */
+ public static final int RESPONDER_STA = 1;
+ /**
+ * Responder is a Wi-Fi Direct Group Owner (GO).
+ */
+ public static final int RESPONDER_P2P_GO = 2;
+ /**
+ * Responder is a Wi-Fi Direct Group Client.
+ */
+ public static final int RESPONDER_P2P_CLIENT = 3;
+ /**
+ * Responder is a Wi-Fi Aware device.
+ */
+ public static final int RESPONDER_AWARE = 4;
+
+
+ /** @hide */
+ @IntDef({
+ CHANNEL_WIDTH_20MHZ, CHANNEL_WIDTH_40MHZ, CHANNEL_WIDTH_80MHZ, CHANNEL_WIDTH_160MHZ,
+ CHANNEL_WIDTH_80MHZ_PLUS_MHZ})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ChannelWidth {
+ }
+
+ /**
+ * Channel bandwidth is 20 MHZ
+ */
+ public static final int CHANNEL_WIDTH_20MHZ = 0;
+ /**
+ * Channel bandwidth is 40 MHZ
+ */
+ public static final int CHANNEL_WIDTH_40MHZ = 1;
+ /**
+ * Channel bandwidth is 80 MHZ
+ */
+ public static final int CHANNEL_WIDTH_80MHZ = 2;
+ /**
+ * Channel bandwidth is 160 MHZ
+ */
+ public static final int CHANNEL_WIDTH_160MHZ = 3;
+ /**
+ * Channel bandwidth is 160 MHZ, but 80MHZ + 80MHZ
+ */
+ public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4;
+
+ /** @hide */
+ @IntDef({PREAMBLE_LEGACY, PREAMBLE_HT, PREAMBLE_VHT})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PreambleType {
+ }
+
+ /**
+ * Preamble type: Legacy.
+ */
+ public static final int PREAMBLE_LEGACY = 0;
+
+ /**
+ * Preamble type: HT.
+ */
+ public static final int PREAMBLE_HT = 1;
+
+ /**
+ * Preamble type: VHT.
+ */
+ public static final int PREAMBLE_VHT = 2;
+
+
+ /**
+ * The MAC address of the Responder. Will be null if a Wi-Fi Aware peer identifier (the
+ * peerHandle field) ise used to identify the Responder.
+ * TODO: convert to MacAddress
+ */
+ public MacAddress macAddress;
+
+ /**
+ * The peer identifier of a Wi-Fi Aware Responder. Will be null if a MAC Address (the macAddress
+ * field) is used to identify the Responder.
+ */
+ public PeerHandle peerHandle;
+
+ /**
+ * The device type of the Responder.
+ */
+ public final int responderType;
+
+ /**
+ * Indicates whether the Responder device supports IEEE 802.11mc.
+ */
+ public final boolean supports80211mc;
+
+ /**
+ * Responder channel bandwidth, specified using {@link ChannelWidth}.
+ */
+ public final int channelWidth;
+
+ /**
+ * The primary 20 MHz frequency (in MHz) of the channel of the Responder.
+ */
+ public final int frequency;
+
+ /**
+ * Not used if the {@link #channelWidth} is 20 MHz. If the Responder uses 40, 80 or 160 MHz,
+ * this is the center frequency (in MHz), if the Responder uses 80 + 80 MHz, this is the
+ * center frequency of the first segment (in MHz).
+ */
+ public final int centerFreq0;
+
+ /**
+ * Only used if the {@link #channelWidth} is 80 + 80 MHz. If the Responder uses 80 + 80 MHz,
+ * this is the center frequency of the second segment (in MHz).
+ */
+ public final int centerFreq1;
+
+ /**
+ * The preamble used by the Responder, specified using {@link PreambleType}.
+ */
+ public final int preamble;
+
+ /**
+ * Constructs Responder configuration.
+ *
+ * @param macAddress The MAC address of the Responder.
+ * @param responderType The type of the responder device, specified using
+ * {@link ResponderType}.
+ * @param supports80211mc Indicates whether the responder supports IEEE 802.11mc.
+ * @param channelWidth Responder channel bandwidth, specified using {@link ChannelWidth}.
+ * @param frequency The primary 20 MHz frequency (in MHz) of the channel of the Responder.
+ * @param centerFreq0 Not used if the {@code channelWidth} is 20 MHz. If the Responder uses
+ * 40, 80 or 160 MHz, this is the center frequency (in MHz), if the
+ * Responder uses 80 + 80 MHz, this is the center frequency of the first
+ * segment (in MHz).
+ * @param centerFreq1 Only used if the {@code channelWidth} is 80 + 80 MHz. If the
+ * Responder
+ * uses 80 + 80 MHz, this is the center frequency of the second segment
+ * (in
+ * MHz).
+ * @param preamble The preamble used by the Responder, specified using
+ * {@link PreambleType}.
+ */
+ public ResponderConfig(@NonNull MacAddress macAddress, @ResponderType int responderType,
+ boolean supports80211mc, @ChannelWidth int channelWidth, int frequency, int centerFreq0,
+ int centerFreq1, @PreambleType int preamble) {
+ if (macAddress == null) {
+ throw new IllegalArgumentException(
+ "Invalid ResponderConfig - must specify a MAC address");
+ }
+ this.macAddress = macAddress;
+ this.peerHandle = null;
+ this.responderType = responderType;
+ this.supports80211mc = supports80211mc;
+ this.channelWidth = channelWidth;
+ this.frequency = frequency;
+ this.centerFreq0 = centerFreq0;
+ this.centerFreq1 = centerFreq1;
+ this.preamble = preamble;
+ }
+
+ /**
+ * Constructs Responder configuration.
+ *
+ * @param peerHandle The Wi-Fi Aware peer identifier of the Responder.
+ * @param responderType The type of the responder device, specified using
+ * {@link ResponderType}.
+ * @param supports80211mc Indicates whether the responder supports IEEE 802.11mc.
+ * @param channelWidth Responder channel bandwidth, specified using {@link ChannelWidth}.
+ * @param frequency The primary 20 MHz frequency (in MHz) of the channel of the Responder.
+ * @param centerFreq0 Not used if the {@code channelWidth} is 20 MHz. If the Responder uses
+ * 40, 80 or 160 MHz, this is the center frequency (in MHz), if the
+ * Responder uses 80 + 80 MHz, this is the center frequency of the first
+ * segment (in MHz).
+ * @param centerFreq1 Only used if the {@code channelWidth} is 80 + 80 MHz. If the
+ * Responder
+ * uses 80 + 80 MHz, this is the center frequency of the second segment
+ * (in
+ * MHz).
+ * @param preamble The preamble used by the Responder, specified using
+ * {@link PreambleType}.
+ */
+ public ResponderConfig(@NonNull PeerHandle peerHandle, @ResponderType int responderType,
+ boolean supports80211mc, @ChannelWidth int channelWidth, int frequency, int centerFreq0,
+ int centerFreq1, @PreambleType int preamble) {
+ this.macAddress = null;
+ this.peerHandle = peerHandle;
+ this.responderType = responderType;
+ this.supports80211mc = supports80211mc;
+ this.channelWidth = channelWidth;
+ this.frequency = frequency;
+ this.centerFreq0 = centerFreq0;
+ this.centerFreq1 = centerFreq1;
+ this.preamble = preamble;
+ }
+
+ /**
+ * Creates a Responder configuration from a {@link ScanResult} corresponding to an Access
+ * Point (AP), which can be obtained from {@link android.net.wifi.WifiManager#getScanResults()}.
+ */
+ public static ResponderConfig fromScanResult(ScanResult scanResult) {
+ MacAddress macAddress = MacAddress.fromString(scanResult.BSSID);
+ int responderType = RESPONDER_AP;
+ boolean supports80211mc = scanResult.is80211mcResponder();
+ int channelWidth = translcateScanResultChannelWidth(scanResult.channelWidth);
+ int frequency = scanResult.frequency;
+ int centerFreq0 = scanResult.centerFreq0;
+ int centerFreq1 = scanResult.centerFreq1;
+
+ // TODO: b/68936111 - extract preamble info from IE
+ int preamble;
+ if (channelWidth == CHANNEL_WIDTH_80MHZ || channelWidth == CHANNEL_WIDTH_160MHZ) {
+ preamble = PREAMBLE_VHT;
+ } else {
+ preamble = PREAMBLE_HT;
+ }
+
+ return new ResponderConfig(macAddress, responderType, supports80211mc, channelWidth,
+ frequency, centerFreq0, centerFreq1, preamble);
+ }
+
+ /**
+ * Creates a Responder configuration from a MAC address corresponding to a Wi-Fi Aware
+ * Responder. The Responder parameters are set to defaults.
+ */
+ public static ResponderConfig fromWifiAwarePeerMacAddressWithDefaults(MacAddress macAddress) {
+ /* Note: the parameters are those of the Aware discovery channel (channel 6). A Responder
+ * is expected to be brought up and available to negotiate a maximum accuracy channel
+ * (i.e. Band 5 @ 80MHz). A Responder is brought up on the peer by starting an Aware
+ * Unsolicited Publisher with Ranging enabled.
+ */
+ return new ResponderConfig(macAddress, RESPONDER_AWARE, true, CHANNEL_WIDTH_20MHZ,
+ AWARE_BAND_2_DISCOVERY_CHANNEL, 0, 0, PREAMBLE_HT);
+ }
+
+ /**
+ * Creates a Responder configuration from a {@link PeerHandle} corresponding to a Wi-Fi Aware
+ * Responder. The Responder parameters are set to defaults.
+ */
+ public static ResponderConfig fromWifiAwarePeerHandleWithDefaults(PeerHandle peerHandle) {
+ /* Note: the parameters are those of the Aware discovery channel (channel 6). A Responder
+ * is expected to be brought up and available to negotiate a maximum accuracy channel
+ * (i.e. Band 5 @ 80MHz). A Responder is brought up on the peer by starting an Aware
+ * Unsolicited Publisher with Ranging enabled.
+ */
+ return new ResponderConfig(peerHandle, RESPONDER_AWARE, true, CHANNEL_WIDTH_20MHZ,
+ AWARE_BAND_2_DISCOVERY_CHANNEL, 0, 0, PREAMBLE_HT);
+ }
+
+ /**
+ * Check whether the Responder configuration is valid.
+ *
+ * @return true if valid, false otherwise.
+ * @hide
+ */
+ public boolean isValid(boolean awareSupported) {
+ if (macAddress == null && peerHandle == null || macAddress != null && peerHandle != null) {
+ return false;
+ }
+ if (!awareSupported && responderType == RESPONDER_AWARE) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ if (macAddress == null) {
+ dest.writeBoolean(false);
+ } else {
+ dest.writeBoolean(true);
+ macAddress.writeToParcel(dest, flags);
+ }
+ if (peerHandle == null) {
+ dest.writeBoolean(false);
+ } else {
+ dest.writeBoolean(true);
+ dest.writeInt(peerHandle.peerId);
+ }
+ dest.writeInt(responderType);
+ dest.writeInt(supports80211mc ? 1 : 0);
+ dest.writeInt(channelWidth);
+ dest.writeInt(frequency);
+ dest.writeInt(centerFreq0);
+ dest.writeInt(centerFreq1);
+ dest.writeInt(preamble);
+ }
+
+ public static final Creator<ResponderConfig> CREATOR = new Creator<ResponderConfig>() {
+ @Override
+ public ResponderConfig[] newArray(int size) {
+ return new ResponderConfig[size];
+ }
+
+ @Override
+ public ResponderConfig createFromParcel(Parcel in) {
+ boolean macAddressPresent = in.readBoolean();
+ MacAddress macAddress = null;
+ if (macAddressPresent) {
+ macAddress = MacAddress.CREATOR.createFromParcel(in);
+ }
+ boolean peerHandlePresent = in.readBoolean();
+ PeerHandle peerHandle = null;
+ if (peerHandlePresent) {
+ peerHandle = new PeerHandle(in.readInt());
+ }
+ int responderType = in.readInt();
+ boolean supports80211mc = in.readInt() == 1;
+ int channelWidth = in.readInt();
+ int frequency = in.readInt();
+ int centerFreq0 = in.readInt();
+ int centerFreq1 = in.readInt();
+ int preamble = in.readInt();
+
+ if (peerHandle == null) {
+ return new ResponderConfig(macAddress, responderType, supports80211mc, channelWidth,
+ frequency, centerFreq0, centerFreq1, preamble);
+ } else {
+ return new ResponderConfig(peerHandle, responderType, supports80211mc, channelWidth,
+ frequency, centerFreq0, centerFreq1, preamble);
+ }
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof ResponderConfig)) {
+ return false;
+ }
+
+ ResponderConfig lhs = (ResponderConfig) o;
+
+ return Objects.equals(macAddress, lhs.macAddress) && Objects.equals(peerHandle,
+ lhs.peerHandle) && responderType == lhs.responderType
+ && supports80211mc == lhs.supports80211mc && channelWidth == lhs.channelWidth
+ && frequency == lhs.frequency && centerFreq0 == lhs.centerFreq0
+ && centerFreq1 == lhs.centerFreq1 && preamble == lhs.preamble;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(macAddress, peerHandle, responderType, supports80211mc, channelWidth,
+ frequency, centerFreq0, centerFreq1, preamble);
+ }
+
+ /** @hide */
+ @Override
+ public String toString() {
+ return new StringBuffer("ResponderConfig: macAddress=").append(macAddress).append(
+ ", peerHandle=").append(peerHandle == null ? "<null>" : peerHandle.peerId).append(
+ ", responderType=").append(responderType).append(", supports80211mc=").append(
+ supports80211mc).append(", channelWidth=").append(channelWidth).append(
+ ", frequency=").append(frequency).append(", centerFreq0=").append(
+ centerFreq0).append(", centerFreq1=").append(centerFreq1).append(
+ ", preamble=").append(preamble).toString();
+ }
+
+ /** @hide */
+ static int translcateScanResultChannelWidth(int scanResultChannelWidth) {
+ switch (scanResultChannelWidth) {
+ case ScanResult.CHANNEL_WIDTH_20MHZ:
+ return CHANNEL_WIDTH_20MHZ;
+ case ScanResult.CHANNEL_WIDTH_40MHZ:
+ return CHANNEL_WIDTH_40MHZ;
+ case ScanResult.CHANNEL_WIDTH_80MHZ:
+ return CHANNEL_WIDTH_80MHZ;
+ case ScanResult.CHANNEL_WIDTH_160MHZ:
+ return CHANNEL_WIDTH_160MHZ;
+ case ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ:
+ return CHANNEL_WIDTH_80MHZ_PLUS_MHZ;
+ default:
+ throw new IllegalArgumentException(
+ "translcateScanResultChannelWidth: bad " + scanResultChannelWidth);
+ }
+ }
+}
diff --git a/wifi/tests/Android.mk b/wifi/tests/Android.mk
index c98e40a..d9f332f 100644
--- a/wifi/tests/Android.mk
+++ b/wifi/tests/Android.mk
@@ -58,6 +58,7 @@
LOCAL_JAVA_LIBRARIES := \
android.test.runner \
+ android.test.base \
LOCAL_PACKAGE_NAME := FrameworksWifiApiTests
LOCAL_COMPATIBILITY_SUITE := device-tests
diff --git a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
index 300d425..72e95b9 100644
--- a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
@@ -25,6 +25,7 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.net.MacAddress;
import android.net.wifi.ScanResult;
import android.net.wifi.aware.PeerHandle;
import android.os.Handler;
@@ -33,8 +34,6 @@
import android.os.test.TestLooper;
import android.test.suitebuilder.annotation.SmallTest;
-import libcore.util.HexEncoding;
-
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -73,13 +72,15 @@
}
/**
- * Validate ranging call flow with succesful results.
+ * Validate ranging call flow with successful results.
*/
@Test
public void testRangeSuccess() throws Exception {
RangingRequest request = new RangingRequest.Builder().build();
List<RangingResult> results = new ArrayList<>();
- results.add(new RangingResult(RangingResult.STATUS_SUCCESS, (byte[]) null, 15, 5, 10, 666));
+ results.add(
+ new RangingResult(RangingResult.STATUS_SUCCESS, MacAddress.BROADCAST_ADDRESS, 15, 5,
+ 10, 666));
RangingResultCallback callbackMock = mock(RangingResultCallback.class);
ArgumentCaptor<IRttCallback> callbackCaptor = ArgumentCaptor.forClass(IRttCallback.class);
@@ -135,7 +136,7 @@
List<ScanResult> scanResults2and3 = new ArrayList<>(2);
scanResults2and3.add(scanResult2);
scanResults2and3.add(scanResult3);
- final byte[] mac1 = HexEncoding.decode("000102030405".toCharArray(), false);
+ MacAddress mac1 = MacAddress.fromString("00:01:02:03:04:05");
PeerHandle peerHandle1 = new PeerHandle(12);
RangingRequest.Builder builder = new RangingRequest.Builder();
@@ -169,7 +170,7 @@
for (int i = 0; i < RangingRequest.getMaxPeers() - 3; ++i) {
scanResultList.add(scanResult);
}
- final byte[] mac1 = HexEncoding.decode("000102030405".toCharArray(), false);
+ MacAddress mac1 = MacAddress.fromString("00:01:02:03:04:05");
// create request
RangingRequest.Builder builder = new RangingRequest.Builder();
@@ -189,11 +190,12 @@
@Test(expected = IllegalArgumentException.class)
public void testRangingRequestPastLimit() {
ScanResult scanResult = new ScanResult();
+ scanResult.BSSID = "00:01:02:03:04:05";
List<ScanResult> scanResultList = new ArrayList<>();
for (int i = 0; i < RangingRequest.getMaxPeers() - 2; ++i) {
scanResultList.add(scanResult);
}
- final byte[] mac1 = HexEncoding.decode("000102030405".toCharArray(), false);
+ MacAddress mac1 = MacAddress.fromString("00:01:02:03:04:05");
// create request
RangingRequest.Builder builder = new RangingRequest.Builder();
@@ -228,7 +230,7 @@
public void testRangingResultsParcel() {
// Note: not validating parcel code of ScanResult (assumed to work)
int status = RangingResult.STATUS_SUCCESS;
- final byte[] mac = HexEncoding.decode("000102030405".toCharArray(), false);
+ final MacAddress mac = MacAddress.fromString("00:01:02:03:04:05");
PeerHandle peerHandle = new PeerHandle(10);
int distanceCm = 105;
int distanceStdDevCm = 10;